Union атака с помощью SQL-инъекций
Когда приложение уязвимо для внедрения SQL и результаты запроса возвращаются в ответах приложения, вы можете использовать ключевое слово UNION
для извлечения данных из других таблиц базы данных. Это широко известно как union атака с помощью SQL-инъекции.
Ключевое слово UNION
позволяет выполнить один или несколько дополнительных запросов SELECT
и добавить результаты к исходному запросу.
Например: SELECT a, b FROM table1 UNION SELECT c, d FROM table2
Этот SQL-запрос возвращает единый результирующий набор с двумя столбцами, содержащий значения из столбцов a
и b
в table1
и столбцов c
и d
в table2
.
Чтобы union запрос работал, должны быть выполнены два ключевых требования:
- Отдельные запросы должны возвращать одинаковое количество столбцов.
- Типы данных в каждом столбце должны быть совместимы между отдельными запросами.
Чтобы выполнить union атаку с помощью SQL-инъекции, убедитесь, что ваша атака соответствует этим двум требованиям. Обычно это выясняется:
- Сколько столбцов возвращается из исходного запроса.
- Какие столбцы, возвращенные из исходного запроса, относятся к подходящему типу данных для хранения результатов введенного запроса.
Определяем количество столбцов в таблице
Когда вы выполняете union атаку с помощью SQL-инъекции, существует два эффективных метода определения того, сколько столбцов возвращается из исходного запроса.
Один из методов включает в себя ввод ряда предложений ORDER BY
и увеличение указанного индекса столбца до тех пор, пока не возникнет ошибка. Например, если точкой ввода является заключенная в кавычки строка в предложении WHERE
исходного запроса, вы должны отправить:
Эта серия полезных запросов, сортирует (упорядочивает) результаты по различным столбцам в полученном наборе данных. Столбец в предложении ORDER BY
может быть указан по его индексу, поэтому вам не нужно знать имена каких-либо столбцов. Когда указанный индекс столбца превышает количество фактических столбцов в результирующем наборе, база данных возвращает сообщение об ошибке, например:
The ORDER BY position number 3 is out of range of the number of items in the select list.
Приложение может фактически вернуть ошибку базы данных в своем HTTP-ответе, но оно также может выдать общий ответ об ошибке. В других случаях он может просто не возвращать никаких результатов вообще. В любом случае, пока вы можете обнаружить некоторую разницу в ответе, вы можете определить, сколько столбцов возвращается из запроса.
Второй метод включает отправку серии полезных нагрузок UNION SELECT
с указанием различного количества нулевых значений:
Если количество нулей не соответствует количеству столбцов, база данных возвращает сообщение об ошибке, например:
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
Мы используем NULL
в качестве значений, возвращаемых из введенного запроса SELECT
, поскольку типы данных в каждом столбце должны быть совместимы между исходным и введенным запросами. Значение NULL
преобразуется во все распространенные типы данных, поэтому оно максимизирует вероятность успешного выполнения полезной нагрузки при правильном подсчете столбцов.
Как и в случае с методом ORDER BY
, приложение может фактически возвращать ошибку базы данных в своем HTTP-ответе, но может возвращать общую ошибку или просто не возвращать результатов. Когда количество нулей совпадает с количеством столбцов, база данных возвращает дополнительную строку в результирующем наборе, содержащую нулевые значения в каждом столбце. Влияние на HTTP-ответ зависит от кода приложения. Если вам повезет, вы увидите некоторое дополнительное содержимое в ответе, например, дополнительную строку в HTML-таблице. В противном случае нулевые значения могут вызвать другую ошибку, такую как исключение NullPointerException
. В худшем случае ответ может выглядеть так же, как ответ, вызванный неправильным количеством нулей. Это сделало бы данный метод неэффективным.
Синтаксис, специфичный для базы данных
В Oracle каждый запрос SELECT
должен использовать ключевое слово FROM
и указывать допустимую таблицу. В Oracle есть встроенная таблица под названием dual
, которую можно использовать для этой цели. Таким образом, введенные запросы в Oracle должны были бы выглядеть следующим образом:
' UNION SELECT NULL FROM DUAL--
Описанные полезные нагрузки используют последовательность комментариев с двойным тире --
для комментирования оставшейся части исходного запроса после точки ввода. В MySQL за последовательностью двойных тире должен следовать пробел. В качестве альтернативы для идентификации комментария можно использовать хэш-символ #
.
Для получения более подробной информации о синтаксисе, специфичном для базы данных, смотрите шпаргалку по SQL инъекциям.
Поиск столбцов с нужным типом данных
Union атака с помощью SQL-инъекции позволяет вам извлекать результаты из введенного запроса. Интересные данные, которые вы хотите получить, обычно представлены в строковой форме. Это означает, что вам нужно найти один или несколько столбцов в исходных результатах запроса, тип данных которых соответствует строковым данным или совместим с ними.
После того как вы определите количество требуемых столбцов, вы можете проверить каждый столбец, чтобы проверить, может ли он содержать строковые данные. Вы можете отправить серию полезных запросов UNION SELECT
, которые по очереди помещают строковое значение в каждый столбец. Например, если запрос возвращает четыре столбца, вы должны отправить:
' UNION SELECT 'a',NULL,NULL,NULL--
' UNION SELECT NULL,'a',NULL,NULL--
' UNION SELECT NULL,NULL,'a',NULL--
' UNION SELECT NULL,NULL,NULL,'a'--
Если тип данных столбца несовместим со строковыми данными, введенный запрос вызовет ошибку базы данных, например:
Conversion failed when converting the varchar value 'a' to data type int.
Если ошибка не возникает, и ответ приложения содержит некоторое дополнительное содержимое, включая введенное строковое значение, то соответствующий столбец подходит для извлечения строковых данных.
Использование union атаки в SQL-инъекции для извлечения данных
Когда вы определили количество столбцов, возвращаемых исходным запросом, и выяснили, какие столбцы могут содержать строковые данные, вы можете получить интересные данные.
Предположим, что:
- Исходный запрос возвращает два столбца, оба из которых могут содержать строковые данные.
- Точка ввода - это заключенная в кавычки строка в предложении
WHERE
. - База данных содержит таблицу под названием
users
со столбцамиusername
иpassword
.
В этом примере вы можете получить содержимое таблицы users
, отправив входные данные:
' UNION SELECT username, password FROM users--
Чтобы выполнить эту атаку, вам необходимо знать, что существует таблица под названием users
с двумя столбцами под названием username
и password
. Без этой информации вам пришлось бы угадывать названия таблиц и столбцов. Все современные базы данных предоставляют способы изучения структуры базы данных и определения того, какие таблицы и столбцы они содержат.
Получение данных из нескольких значений в одном столбце
В некоторых случаях запрос как в предыдущем примере может возвращать только один столбец.
Вы можете получить несколько значений вместе в одном столбце, объединив значения. Вставив в качества разделителя определённый символ, позволяющий разделить объединенные значения. Например, в Oracle вы могли бы выполнить запрос:
' UNION SELECT username || '~' || password FROM users--
При этом используется оператор ||
, который является оператором конкатенации строк в Oracle. Введенный запрос объединяет значения полей username
и password
, разделенных символом ~
.
Результаты запроса содержат все имена пользователей и пароли, например:
Разные базы данных используют разный синтаксис для выполнения конкатенации строк. Для получения более подробной информации смотрите шпаргалку по SQL инъекциям.