Слепая быстрота. Новейшие методы Blind SQL InjectionQwazar (hronous@mail.ru) Каждый раз, натыкаясь на слепую SQL-инъекцию, ты представляешь себе долгие минуты ожидания получения результатов из базы. Все знают, что процесс работы ускорить невозможно. Да неужели? Прочитав эту статью, ты заставишь свои инъекции отрабатывать по максимуму и станешь реальным SQL-гуру. Основной проблемой при работе с Blind SQL Injection является огромное количество запросов, которое необходимо послать на сервер для получения символов из БД. А соответственно - долгое время работы скрипта и большое количество записей в логах. Вручную получать данные из БД практически нереально, поэтому процесс работы с такими инъекциями нужно автоматизировать. Сейчас мы рассмотрим некоторые варианты подобной автоматизации. Полный переборЭто самый простой, самый тупой и самый медленный способ получения символов из базы данных. Для получения обычного MD5-хеша может потребоваться отправить до 512 запросов на сервер, а для получения логина - еще больше. Именно этот метод новички применяют в своих первых эксплойтах. Реализация указанного способа выглядит приблизительно так:
Принцип работы прост - для каждого символа сравниваем значение его ASCII-кода со всеми возможными значениями символов. Если выполняется некоторое условие, то символ найден, и его можно выводить на экран. Если условие не выполняется - ищем дальше. Очевидно, что плюсов у этого метода нет. Совсем. За исключением того, что накалякать код такого скрипта очень просто. Но разве это то, что нужно настоящему хакеру? Оставим этот способ киддисам и будем двигаться дальше. Бинарный (двоичный) поискКаждый уважающий себя программист знает о методе под названием бинарный, или двоичный, поиск. Этот метод используется для поиска позиции элемента в отсортированном массиве. И именно он применяется почти во всех адекватных скриптах, программах и эксплойтах, работающих со слепыми SQL-инъекциями. Алгоритм работает следующим образом:
А если рассматривать реализацию на языке программирования, то вот пример функции, реализующей поиск нужного символа этим методом:
Рассмотрим этот способ на примере получения из базы MD5-хеша юзера. При этом учтем следующие условия:
Запускаем алгоритм:
Таким образом, в зависимости от конкретной реализации алгоритма, мы отправляем до 5-6 запросов на определение символа. И это в худшем случае, так как символ Использование find_in_set() и подобных функцийФункция find_in_set(str,strlist) используется для поиска подстроки среди списка строк, разделенных символом ',' и возвращает номер той строки из списка, которая равна переданному аргументу. То есть: Код символа из базы данных можно узнать при помощи запроса: XXXXXXXXXX В результате мы получаем номер символа во множестве '0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f'. К примеру, для символа 'b', этот запрос вернет 12. А теперь подумаем, что же можно из этого выжать? Для того чтобы принять результаты запроса, мы должны как-то научиться принимать числа, являющиеся результатом. Но непосредственно при слепой SQL-инъекции мы этого сделать не можем. А что, если мы имеем дело с инъекцией, к примеру, в скрипте отображения новостей, и в зависимости от id, переданного скрипту, будем видеть разные странички? Тогда боевой запрос, нужный для получения символов из MD5, будет выглядеть вот так: Тогда, в зависимости от номера символа в строке '0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f', мы будем видеть новость с id, соответствующим символу пароля. Для удобства использования на практике нужно:
То есть, для получения MD5-хеша, нам потребуется выявить 16 страниц с уникальными id, по одной странице для каждого символа алфавита, а также отправить 32 запроса для определения значения каждого символа. В итоге, при использовании этого метода нам потребуется отправить всего 48 запросов на сервер, 16 из которых никакого подозрения читающего логи админа вызвать не могут. Изначально этот метод предложили +toxa+ и madnet. Они же заметили, что помимо функции find_in_set для реализации подобной атаки можно использовать функции Способ работает быстро, но обладает рядом недостатков. К примеру, на сайте идентификаторы новостей могут быть распределены неравномерно, то есть скрипт приходится затачивать под каждый сайт индивидуально. Еще одной проблемой является то, что для большого количества символов в алфавите нужно большое количество уникальных страниц, которые не всегда присутствуют. В общем, мотаем на ус и двигаемся дальше. Использование find_in_set() + more1rowЕсли хорошенько поиграться с методом, предложенным выше, можно заметить, что все его минусы сводятся к тому, что далеко не на всех сайтах возможно получить достаточное количество различных страниц, зависящих от одного параметра. Решим эту проблему. Вспомним метод, предложенный Elekt'ом в ][ #111, который основан на использовании ошибки «Subquery returns more than 1 row». Суть метода заключается в том, чтобы заставить скрипт выводить ошибку SQL в зависимости от результата SQL-запроса. На данный момент, чтобы спровоцировать БД на вывод ошибки, наиболее часто используется запрос: – который вернет ошибку: Также ZaCo нашел альтернативный вариант запроса, который провоцирует БД на вывод ошибки в зависимости от условия:
В том случае, если версия MySql не равна 5, этот запрос вернет ошибку: Немного порывшись в исходниках MySql и погуглив, можно найти еще 9 ошибок, которые возвращает неправильный regexp. Итого, от сервера мы можем получить 11 видов ошибок + 1 состояние, когда ошибки нет:
Пока просто примем это во внимание. Теперь самое время вспомнить о функции find_in_set. Если искомый символ есть во множестве подстрок, она вернет номер подстроки, если нет - вернет 0. Попробуем привязать результат работы этой функции к различным кодам ошибок и передадим вот такой запрос:
В результате, если первый символ пароля находится во множестве 'a,b,c,d,e,f,1,2,3,4,5,6', то запрос вернет: А если не находится, то: При каждом запросе по коду ошибки мы можем узнать, к какой группе принадлежит символ! Напишем скрипт, использующий данный метод. Для составления оптимального запроса нужно сгруппировать символы алфавита так, чтобы количество обращений к серверу было минимальным. Рассмотрим задачу на примере MD5. Мы знаем, что у нас могут присутствовать только символы из диапазона [0-9,a-f]. Также мы знаем, что количество групп символов равно двенадцати, ведь всего наш запрос может вернуть одиннадцать видов ошибок и одно состояние, когда ошибки нет. Для случая с MD5 оптимальной расстановкой символов по состояниям, к примеру, будет:
При каждом запросе к серверу мы узнаем номер группы, в которой находится символ, хранящийся в БД. В итоге, если символ находится в группах 02-11, – мы узнаем значение этого символа с помощью всего одного запроса. Если нам не повезло и символ находится в группе 01, то перед отправкой следующего запроса, рассортируем символы из этой группы по состояниям и сразу же узнаем значение интересующего нас символа:
Итоговый алгоритм работы по этому методу выглядит несложно:
В соответствии с алгоритмом составляем запрос. И замечаем, что ошибки, которые мы собираемся использовать, обладают парой особенностей. Первая заключается в том, что запрос:
вернет нужную нам ошибку, только если мы его будем передавать на сервер именно в таком виде. То есть, все вложенные условия нужно добавлять внутрь этого if, а также в начале всех остальных выражений regexp нужно добавлять символ «}». Иначе, независимо от содержания остальных подзапросов, мы будем получать лишь ошибку: «#1139 - Got error 'repetition-operator operand invalid' from regexp». Вторая особенность заключается в том, что запрос:
возвращающий ошибку «Got error 'empty (sub)expression' from regexp», работает, как хочется нам только при наличии пустого подзапроса в regexp или так: 'a|', когда после символа '|' отсутствует что бы то ни было. Поэтому, с учетом первой особенности, будем использовать именно этот вид подзапроса. Теперь попробуем собрать всю известную нам информацию вместе, и для выуживания MD5-хеша получаем итоговый запрос:
В результате, этот запрос не вернет ошибки, если символ из базы данных является одним из символов '0,c,d,e,f', а вернет ошибку «Subquery returns more than 1 row», если в базе данных лежит цифра 1. Также запрос вернет ошибку 'invalid repetition count(s)', если в базе лежит символ '2'. И так далее. Итак, мы добились того, чего хотели - запрос при помощи 11 различных видов ошибок сообщает нам, какой именно символ лежит в базе данных. Мы получаем быстродействие, превышающее скорость работы всех остальных методов работы с Blind SQL Injection. Для выуживания MD5-хеша нам потребуется около 42 запросов, а это уже на порядок быстрее, чем в тех методах, которые используют сейчас. Мало того, если найти еще 4 запроса, при которых ошибка будет возникать во время выполнения, то на получение всего хеша нам потребуется уже 32 запроса. А это значит – 1 запрос на 1 символ. Раньше о подобном можно было только мечтать. Понятно, что подобные SQL-обращения крайне тяжело составлять вручную, поэтому на диске ты найдешь скрипт, который умеет составлять запросы для алфавитов любой длины и при любом количестве известных ошибок. OutroНа самом деле, существуют еще возможности ускорить процесс работы со слепыми SQL-инъекциями. Осталось только их найти. Главное, не зацикливаться на «дедовских» методах. Относиться ко всему, что придумали хакеры предыдущих поколений, надо, как к деталям мозаики, сложив которые воедино, можно выйти на совершенно новый уровень WARNINGВнимание! Информация представлена исключительно с целью ознакомления! Ни автор, ни редакция за твои действия ответственности не несут! WWW
INFOБольшим преимуществом последнего из перечисленных методов является то, что он с тем же успехом может работать и в INSERT, и в UPDATE запросах. DVDНа диске ты сможешь найти скрипты для работы с SQL-инъекциями с использованием описанных в статье методов. |