Перейти к содержанию

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 1--
' ORDER BY 2--
' ORDER BY 3--
и так далее...

Эта серия полезных запросов, сортирует (упорядочивает) результаты по различным столбцам в полученном наборе данных. Столбец в предложении ORDER BY может быть указан по его индексу, поэтому вам не нужно знать имена каких-либо столбцов. Когда указанный индекс столбца превышает количество фактических столбцов в результирующем наборе, база данных возвращает сообщение об ошибке, например:

The ORDER BY position number 3 is out of range of the number of items in the select list.

Приложение может фактически вернуть ошибку базы данных в своем HTTP-ответе, но оно также может выдать общий ответ об ошибке. В других случаях он может просто не возвращать никаких результатов вообще. В любом случае, пока вы можете обнаружить некоторую разницу в ответе, вы можете определить, сколько столбцов возвращается из запроса.

Второй метод включает отправку серии полезных нагрузок UNION SELECT с указанием различного количества нулевых значений:

' UNION SELECT NULL--
' UNION SELECT NULL,НУЛЕВОЙ--
' UNION ВЫБИРАЕТ NULL, NULL, NULL-- 
и т.д.

Если количество нулей не соответствует количеству столбцов, база данных возвращает сообщение об ошибке, например:

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, разделенных символом ~.

Результаты запроса содержат все имена пользователей и пароли, например:

...
administrator~s3cure
wiener~peter
carlos~montoya
...

Разные базы данных используют разный синтаксис для выполнения конкатенации строк. Для получения более подробной информации смотрите шпаргалку по SQL инъекциям.