5.4. Эксплуатация SQLi – метод UNION-based

 

Введение в методы эксплуатации

После того, как уязвимость была найдена и подтверждена, мы можем её использовать для получения содержимого БД или иначе говоря, проэксплуатировать уязвимость. Для этого применяют различные SQL выражения, так называемые пейлоады (payloads). Существуют различные техники эксплуатации, некоторые из которых мы рассмотрим далее.

Для начала рассмотрим самый простой пейлоад на примере уязвимости в авторизации пользователя в Juice Shop. Для входа на сайт требуется знать email пользователя, однако существует способ войти на сайт и не зная правильный логин. Рассмотрим оба варианта.

Так как мы не знаем email пользователей, то нам остается изучить сам сайт на наличие электронных адресов. К счастью, нам доступны некоторые адреса в отзывах и комментариях к товарам:

Отображение отзывов пользователей и их email

Из предыдущего урока нам известен сам SQL запрос, который выглядит так: SELECT * FROM Users Where email=’email пользователя’ AND password=’хэш пароля’ AND deletedAt IS NULL. Если каким-нибудь образом мы удалим правую часть выражения после email, то сможем легко залогиниться, зная только сам логин. Наиболее подходящий пейлоад будет  Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.’--. В поле пароля можно вписать любое значение, оно никак не влияет на результат. Итоговое выражение на сервере будет выглядеть так:

SELECT * FROM Users Where email=’Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.

Благодаря символу комментирования мы смогли отсечь мешающую часть выражения и тем самым войти в систему в качестве администратора.

Теперь посмотрим, что делать, если логин нам неизвестен. Для этого нам подойдет пейлоад 1’ OR 1=1--. Здесь мы добавили условие, которое всегда истинно, а значит мы также сможем залогиниться. Однако в данном случае будет выбран самый первый пользователь в записях БД. Иногда может понадобиться ограничить вывод только одной записью. Для этого просто добавим оператор LIMIT. В итоге у нас получится запись 1’ OR 1=1 LIMIT 1--.

Это был лишь небольшой пример. В зависимости от ситуации и конфигурации уязвимого приложения применяют одну из следующих техник для эксплутации уязвимости:

  • UNION – объединение двух и более запросов оператором UNION.
  • Error-based – намеренный вызов сообщения об ошибке, в которой будет отображаться требуемая информация.
  • Time-based – вызов задержки, если сработало определенное условие. В основном применяется в слепой инъекции Blind SQLi.
  • Stacked (batched) queries – объединение нескольких запросов для последовательного выполнения. Запросы независимы друг от друга.
  • Out-Of-Band – передача требуемых данных на внешний сервер, который находится под нашим контролем. Это может быть веб или DNS сервер. Данная техника также применяется в Blind SQLi.

 

Техника UNION-based

Оператор UNION в SQL выражениях используется для объединения двух и более запросов одинаковой структуры. Например, запросы SELECT name, surname FROM users и SELECT order, price FROM goods можно объединить в один запрос SELECT name, surname FROM users UNION SELECT order, price FROM goods. Результат работы обоих запросов будет выводиться в одном потоке. Если мы найдем уязвимую точку доступа, то можем составить свой запрос на основе оператора UNION. Данная техника применима в тех случаях, когда содержимое базы данных отображается на веб странице. Это может быть любая таблица, которая через GET или POST запрос отображает тот или иной контент. Это может быть поиск по сайту или отображение товаров и постов в блоге.

Чтобы техника UNION сработала нужно соблюсти 2 условия: количество колонок (столбцов) в обоих SQL запросах должны совпадать и типы выводимых данных в этих столбцах также должны быть одинаковы. Поясним все вышеописанное на примере приложения bWAPP, которое использует MySQL.

Открываем приложение, логинимся (bee/bug) и затем в правом верхнем углу выбираем SQL Injection (Search/GET) и нажимаем на кнопку Hack:

Выбор теста в bWAPP

Уязвимость присутствует в системе поиска по сайту через GET запрос. Для начала рассмотрим, как работает поиск. Введите man или любое другое слово:

Демонстрация работы поиска

Попробуем в поле поиска ввести следующий запрос: 1’ UNION SELECT database() #

Функция database() в MySQL позволяет выводить имя текущей базы данных, однако система вывела ошибку запроса:

Определение количества колонок в SQL запросе

Это связано с тем, что во втором выражении указан только один столбец.

Как же узнать точное количество параметров (столбцов) в SQL выражении?

На первый взгляд может показаться, что в запросе всего 5 столбцов, так как в таблице 5 колонок. Однако на деле столбцов может быть больше, так как некоторые выводимые параметры могут быть для нас скрыты по тем или иным причинам. Поэтому, чтобы определить точное количество параметров в SQL запросе, мы можем воспользоваться 2 методами.

 

1-й способ

Допустим у нас имеется запрос SELECT столбец_1, столбец_2, столбец_3 FROM таблица. Если мы к нему добавим запрос UNION SELECT 1, 2, 3 или UNION SELECT null, null, null, то система не выдаст ошибки, то есть мы соблюли условие с равным количеством параметров.

Теперь применим данную технику к нашему примеру. Если введем запрос 1’ UNION SELECT 1, 2, 3, 4, 5 #, то система снова выдаст ошибку. Поэтому будет увеличивать количество столбцов в каждой новой попытке, пока не получим положительный результат.

После ввода запроса 1’ UNION SELECT 1, 2, 3, 4, 5, 6, 7 # отображается следующий результат:

Определение количества колонок в SQL запросе

В таблице отображаются введенные цифры, причем некоторые из них скрыты. Таким образом мы определили, что в запросе присутствуют 7 параметров (столбцов).

 

2-й способ

Второй способ основан на операторе сортировки ORDER BY. Данный оператор принимает имя столбца либо его номер в SQL запросе. Например, у нас имеется запрос SELECT name, price, stock FROM goods. Мы можем отсортировать вывод по имени столбца:

SELECT name, price, stock FROM goods ORDER BY name

или по его номеру:

SELECT name, price, stock FROM goods ORDER BY 1.

Если указать несуществующий номер, то система выдаст ошибку. Именно на этом принципе и основан метод определения количества столбцов.

Для начала вводим небольшое число, а затем увеличиваем его с каждой новой попыткой до тех пор, пока не получим ошибку. В нашем примере мы предполагаем, что столбцов 5 (по количеству столбцов в таблице), поэтому вводим 6: man’ ORDER BY 6 #. Затем увеличиваем это число и после ввода 8 получаем ошибку:

Определение количества колонок в SQL методом сортировки

Теперь, когда нам известно количество параметров, мы можем составить запрос, чтобы получить некоторые данные из БД. Для начала попробуем узнать имя БД, версию СУБД и имя пользователя БД. Для этого составим такой запрос:

1' UNION SELECT 1, database(), user(), version(), 5, 6, 7 #:

Отображение названия и версии базы данных

Теперь, зная имя БД, мы можем пойти дальше и узнать какие таблицы имеются в данной базе данных, а также сможем узнать, что содержатся в каждой из таблиц.

В MySQL список таблиц в конкретной БД определяется следующим запросом:

SELECT table_name FROM information_schema.tables WHERE table_schema=’название_БД’

Поменяем наш запрос с учетом новых условий:

1’ UNION SELECT 1, table_name, 3, 4, 5, 6, 7 FROM information_schema.tables WHERE table_schema=’bwapp’ #

Определение таблиц в текущей базе данных

БД bwapp содержит 4 таблицы. Думаю, наиболее интересная таблица будет users. Чтобы просмотреть ее содержимое нам необходимо знать какие колонки у нее имеются.

В этом нам поможет такой запрос:

SELECT column_name, FROM information_schema.columns WHERE table_schema=’название_БД’ AND table_name=’название_таблицы’.

Снова применим новые условия:

1’ UNION SELECT 1, column_name, 3, 4, 5, 6, 7 FROM information_schema.columns WHERE table_schema=’bwapp’ AND table_name=’users’ #

Определение названий столбцов в таблице bwapp

Выглядит довольно интересно! Посмотрим, что внутри данной таблицы:

1’ UNION SELECT 1, login, password, secret, admin, 6, 7 FROM users #

Содержимое таблицы users

А внутри у нас 2 пользователя и оба являются администраторами, причем у обоих одинаковые пароли.

Таким способом, используя технику UNION, вы можете пройтись по всей базе данных.