Как это обычно бывает, во время простого серфинга мне попался сайт
www.gamestyle.ru. Чутье мне подсказало - где-то тут есть ошибки.
Недолго думая я приступил к анализу. Зарегистрировал пользователя tester,
вошел в систему и начал смотреть, выискивая взглядом различные уязвимые места.
После недолгого осмотра ресурса был найден скрипт статистики www.gamestyle.ru/rating.php,
которому передавался параметр id. Подставив символ ' к значению я получил
грязное ругательство mysql. Причем он не просто ругнулся, а показал весь запрос,
что было мне только на руку, ибо я видел сколько полей требуется.
Запрос был изменен до простого:
www.gamestyle.ru/rating.php?act=catselect&id=-1/**/UNION/**/SELECT/**/1,2
который и показал мне цифру 2 на страничке.
После этого цифру 2 я заменил на version(), чтоб точнее определить, с чем я
имею дело.
Неплохо было бы найти в базе табличку с юзерами. Префикс, судя по всему,
отсутствовал, но проверить было бы неплохо. "Соседний" скрипт оказался уязвим
тоже и он с радостью выдал мне названия таблиц "ut_game_settings", "ut_game_genres",
"ut_companies", что привело к мысле о префиксе "ut_" у таблиц этого непонятного
мне движка.
После этих рассуждений я смело вернулся к бажному скрипту в который и
подставил SELECT из таблицы ut_users. И я не прогадал. Действительно, по запросу
www.gamestyle.ru/rating.php?act=catselect&id=-1/**/UNION/**/SELECT/**/1,name/**/FROM/**/ut_users
я получил пустую строку. Но как имя пользователя может быть пустым?
Единственный вариант — поле name в таблице ut_users — это реальное имя
пользователя, а не его логин.
Я попробовал выдернуть первый пароль из базы. Запрос
www.gamestyle.ru/rating.php?act=catselect&id=-1/**/UNION/**/SELECT/**/1,password/**/FROM/**/ut_users
вернул мне обычный md5-хэш из базы. Но логин оставался неизвестным. Стоило
лишь предположить, что в таблице существует поле login. И вот чудо -
интуиция меня не подвела! Запрос
www.gamestyle.ru/rating.php?act=catselect&id=-1/**/UNION/**/SELECT/**/1,login/**/FROM/**/ut_users
выплюнул имя пользователя Outlaw.
Но что бы сделать с этим хэшем? Логично было бы посмотреть куки. В них
хранилось имя пользователя и хэш пароля. Я решил, что раз ошибки с
SQL-инъекциями у программиста имеются — то и тут меня может ожидать удача. Имя
пользователя в куках было изменено на Outlaw, пароль — на полученный ранее хэш.
Так же, на всякий пожарный случай, я удалил из куков данные о своей сессии. И к
моей великой радости по запросу www.gamestyle.ru/admin/ я попал в админ-панель
портала!
Далее я мог бы сделать что угодно. Но я решил ограничится мелким комментарием
в теле последней на тот момент новости и письменным уведомлением админа.
Подведем итоги. Взлом был бы невозможен, если бы задуманный целый параметр id
приводился к типу int. Также взлом был бы затруднен если бы "по соседству" не
был бы найден скрипт, плюющий ошибками. Кстати, в том скрипте уязвимость почти
бесполезная и UNION сделать не удастся, т.к. тогда и первый, и второй запрос
надо было бы взять в скобки, т.к. в первом запросе присутствует ORDER BY.
Взлом был бы практически невозможен, если бы ошибки mysql не выводились. Хотя
можно было бы попробовать и вслепую, но тогда префикс к таблице узнать было бы
куда сложнее. Так же взлом был бы не возможен, если бы в куках хранились не хэши
из базы, а хэши от соли+хэша, т.е. md5($salt+$hash).
В принципе, все ошибки — тривиальны, и сколько не говори программистам о
безопасности — среди них всегда будут находится самоучки, выдающие такие
"движки".
P.S.: Данная статья представлена в качестве пищи для ума, а не руководства к
действию. В любом случае, за любые ваши действия, совершенные после прочтения
этой статьи, автор ответственности не несет. И если вы разработчик подобных
Web-приложений — не учитесь на своих ошибках, учитесь на чужих.