Добиваем SQL. Новейшие способы работы с инъекциямиQwazar (qwazar@antichat.net) Не прошло и трех дней после сдачи моей прошлой статьи, как в голове родилась совершенно новая и куда более эффективная методика работы с Blind SQL Injection. Если ты помнишь, я рассказывал о том, как существенно уменьшить количество запросов к серверу при работе с уязвимостями такого рода. Сегодня я покажу поистине революционные приемы инъектирования. А ты внимательно слушай и конспектируй. Разбираемся с именами столбцовНачались мои исследования с попытки решить вторую основную проблему тех, кто работает с инъекциями в MySQL. Она заключается в невозможности получить имена таблиц и столбцов в MySQL 4-й ветки, не прибегая к полному перебору. Насколько нам всем известно, в этой ветке начисто отсутствует системная таблица Забиваем текст в поисковик и видим: эту ошибку можно получить, если задать уже существующее имя колонки в оператор ALTER TABLE, или если неправильно воспользоваться оператором JOIN. Вариант с ALTER TABLE не подходит, так как его невозможно использовать в SELECT-запросе. Попробуем вариант с JOIN. Для начала выясним, когда именно эта ошибка возникает в SELECT-запросе. Посмотрев документацию, выясняем, что эта ошибка возникает тогда, когда ты при помощи оператора SELECT пытаешься получить имя какой-нибудь колонки (к примеру, id) и тут оказывается, что колонок с именем id несколько. Оператор SELECT теряется и выплевывает ошибку. Мол, колонок с именем 'id' несколько, и он не знает, какая именно тебе нужна. Теперь вспомним о том, что оператор JOIN используется для связывания двух таблиц между собой. Запускаем запрос с использованием JOIN:
И видим, что он вернул нам содержимое таблиц `users` и `news` в виде одной таблицы, причем имена колонок в таблицах остались прежними. То есть, у нас в выводимом результате – две колонки с именем 'id'. Попробуем получить значение поля 'id' из таблицы, составленной выше. Не забываем о том, что для сложных запросов MySQL требует указания алиасов для каждой таблицы, участвующей в запросе.
Отлично! Получили то, что хотели, осталось подумать, как при помощи подобного запроса получить имена всех столбцов, к примеру, таблицы `users`. Джойним ее саму с собой:
На выходе получаем имя первого столбца таблицы. Думаем, как получить остальные. Снова смотрим в документацию и находим оператор USING, который используется для указания списка столбцов, которые присутствуют в обеих таблицах:
семантически идентично выражению ON, например:
То есть, объединив таблицы `news` и `users` и используя оператор USING() с параметром 'id', мы получим результирующую таблицу, в которой столбец с именем 'id' будет присутствовать только один раз. Пробуем:
Действительно, видим только один столбец с именем 'id', а значит и попытка получить столбец с именем 'id' из этой таблицы никакой ошибки не спровоцирует. Применим этот оператор для получения имен остальных полей из таблицы `users`, с учетом того, что имя 'id' мы уже знаем:
Ага, узнали еще одно имя столбца - 'name', пробуем дальше:
Узнаем имя третьего столбца. И так, один за другим, выявляем имена столбцов в этой таблице. В конце, когда выясним все имена, ошибки не будет, и запрос выполнится успешно.
Делаем вывод, что в таблице `users` присутствуют столбцы 'id', 'name', 'passwd', 'is_admin'. Вроде бы все хорошо, но... метод не срабатывает на MySQL 4-й версии. Выясняется, что в четвертой версии при таком запросе возникает совершенно другая ошибка. Следовательно, все описанное выше может использоваться, только если по каким-либо причинам мы не можем воспользоваться таблицей Взгляд под другим угломВозможность получать имена столбцов без использования INFORMATION_SCHEMA – это, конечно, возможность полезная, но такая необходимость возникает довольно редко. Разве что в слепых SQL-инъекциях, с возможностью вывода ошибки, где стандартный процесс получения значений занимает достаточно много времени. А тут пара запросов и все нужные значения получены. Хотелось бы выжать из этой ошибки большее... Недавно мне в аську постучался jokester (Джок, большой тебе привет!) и предложил следующую идею: «А почему бы не попробовать выводить значение какого-либо поля из базы данных в тексте ошибки целиком, не прибегая к классическому использованию more 1 row?». «Идея отличная», - согласился я. Он начал исследовать варианты составления запросов с использованием ORDER BY, которые при неправильном значении сортируемого поля выводят ошибку:
Я же вспомнил о методе вывода имен колонок с использованием JOIN. Через некоторое время мы оба пришли к тому, что нужно найти какой-нибудь способ заставить базу данных воспринимать значение поля как имя колонки. Это обуславливается тем, что запросы, которые ругаются на неправильное имя колонки, есть, а запросов, которые ругаются на неправильные данные в таблице и при этом их выводят, - нет. Отлично, задача поставлена, зарываемся в документацию. Находим интересную функцию в разделе «Miscellaneous Functions», с пометкой «for internal use only». Функция называется NAME_CONST(). Используется так: NAME_CONST(name,value). Результатом работы станет значение 'value' в столбце с именем 'name':
Как раз то, что нужно! Проверим, возможно ли вместо значения 'value' выполнить какой-нибудь запрос. Достанем, к примеру, поле 'passhash' из таблицы 'users':
А теперь используем этот запрос в методе получения имен полей, без использования INFORMATION_SCHEMA. Аккуратненько составляем запрос, подставив вызов функции NAME_CONST вместо имени таблицы, в которой узнаем имена столбцов. Не забываем добавлять алиасы к каждой используемой таблице, и стараемся не запутаться в скобочках. Запускаем:
Вот мы и добились, чего хотели. Теперь мы знаем, как достать из базы данных любое поле за один запрос! Попробуем вытащить больше чем одно поле при помощи функции CONCAT(), назначение которой объединять две и более строк. Например: Так мы и получили два поля за один запрос. К сожалению, бесконечно увеличивать количество выводимых полей невозможно, так как вывести более 64 символов не получится. Но эта проблема решаема, если использовать функцию SUBSTRING(), описание к которой ты без проблем найдешь в официальной документации. ЗаключениеДалеко не все методики работы с уязвимостями исследованы до конца, вариантов упростить свою работу еще бесчисленное множество. Поэтому я бы хотел посоветовать всем хакерам иногда отвлекаться от тривиального взлома и уделять часть своего времени новым исследованиям. Ведь хакер это, в первую очередь, исследователь, не так ли? WARNINGВнимание! Информация представлена исключительно с целью ознакомления! Ни автор, ни редакция за твои действия ответственности не несут! WWW
INFOЭти методы можно использовать и в обычных инъекциях. При их использовании не придется подбирать количество колонок в запросе. |