SQL-инъекции: UNION атаки
Когда приложение уязвимо для SQL-инъекций и результат SQL запроса возвращаются в ответах приложения, можно использовать ключевое слово UNION для извлечения данных из других таблиц базы данных. Это приводит к SQL-инъекции с UNION атакой.
Ключевое слово UNION
позволяет выполнить один или несколько дополнительных запросов SELECT
и добавить результаты к исходному SQL запросу. Например:
SELECT a, b FROM table1 UNION SELECT c, d FROM table2
Этот SQL запрос вернёт один результирующий набор с двумя столбцами, содержащими значения из столбцов a
и b
в table1
и столбцов c
и d
в table2
.
Чтобы выполнился UNION
запрос, должны быть выполнены два ключевых требования:
- Отдельные запросы должны возвращать одинаковое количество столбцов.
- Типы данных в каждом столбце должны быть совместимы между отдельными запросами.
Чтобы выполнить SQL-инъекцию с UNION атакой, необходимо убедиться, что ваша атака соответствует этим требованиям. Обычно это включает в себя выяснение:
- Сколько столбцов возвращается из исходного запроса?
- Какие столбцы, возвращённые исходным запросом, имеют подходящий тип данных для хранения результатов выведенного запроса?
Как определить количества столбцов, необходимых для SQL-инъекции с UNION атакой
При выполнении SQL-инъекции с UNION атакой существует два эффективных метода определения количества столбцов, возвращаемых исходным запросом.
Первый метод включает в себя вставку ряда выражений 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
с указанием различного количества значений NULL
:
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
etc.
Если количество NULL
не соответствует количеству столбцов, база данных возвращает ошибку, например:
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
Опять, приложение может на самом деле вернуть это сообщение об ошибке или может просто вернуть общею ошибку, или никаких результатов. Когда количество NULL
совпадает с количеством столбцов, база данных возвращает дополнительную строку в результирующем наборе, содержащую значение NULL
в каждом столбце. Влияние на результирующий HTTP-ответ зависит от кода приложения. Если вам повезёт, вы увидите дополнительный контент в ответе, например дополнительную строку в HTML таблице. В противном случае значения NULL
могут вызвать различные ошибки, например NullPointerException
. В худшем случае ответ может быть неотличим от ответа, вызванного неправильным количеством нулей, что делает этот метод определения количества столбцов неэффективным.
Примечание
Причина использования
NULL
в качестве значений возвращаемых из внедрённого запросаSELECT
, заключается в том, что типы данных в каждом столбце должны быть совместимы между исходным и внедрённым запросами. Поскольку значениеNULL
может быть преобразовано во все часто используемы типы данных, использованиеNULL
увеличивает вероятность того, что полезная нагрузка будет успешной, если количество столбцов правильное.В Oracle каждый запрос
SELECT
должен использовать ключевое словоFROM
и указывать допустимую таблицу. В Oracle есть встроенная таблица, называемаяdual
, которую можно использовать для этой цели.' UNION SELECT NULL FROM DUAL--
Описанные полезные нагрузки используют последовательность комментариев с двойным тире
--
, для комментирования оставшейся части исходного запроса после точки внедрения. В MySQL за последовательностью двойных тире должен следовать пробел. Кроме того, для обозначения комментария можно использовать символ решётки/хэш#
.
Дополнительная информация о синтаксисе специфичном для основных (Oracle, Microsoft, PostgreSQL и MySQL) баз данных есть в шпаргалке по SQL-инъекциям
Поиск столбцов с полезным типом данных в SQL-инъекции с UNION атакой
Причина выполнения SQL-инъекции с UNION атакой заключается в том, чтобы иметь возможность получить результаты внедрённого запроса. Как правило, интересные данные, которые вы хотите получить будут в форме строки. Поэтому нужно найти один или несколько столбцов в исходных результатах, тип данных которых является строковым или совместимым с ним типом.
Определив количество столбцов, вы можете протестировать каждый столбец и проверить, может ли он содержать строковые данные, отправив серию полезных данных через 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.
Если ошибка не возникает, а ответ приложения содержит некоторое дополнительное содержимое, включая введённое строковое значение, то соответствующий столбец подходит для получения строковых данных.
Использование SQL-инъекции с UNION атакой для извлечения интересных данных
Когда вы определили количество столбцов возвращаемых исходным SQL запросом, и нашли, какие столбцы могут содержать строковые данные, вы можете получить интересные данные.
Предположим, что:
- Исходный запрос возвращает два столбца, оба из которых могут содержать строковые данные.
- Точка внедрения — это строка в кавычках в выражение
WHERE
. - База данных содержит таблицу с названием
users
со столбцамиusername
иpassword
.
В этой ситуации вы можете получить содержимое таблицы users
, отправив ввод:
' UNION SELECT username, password FROM users--
Конечно, ключевая информация, необходимая для выполнения этой атаки, заключается в том, что существует таблица users
с двумя столбцами username
и password
. Без этой информации вам пришлось бы попытаться угадать имена таблиц и столбцов. Фактически, все современные базы данных предоставляют способы изучения структуры базы данных, для определения какие таблицы и столбцы она содержит.
Получение нескольких значений в одном столбце
В предыдущем примере предположим, что SQL запрос возвращает только один столбец.
Вы можете легко получить несколько значений вместе в этом одном столбце, объединив значения вместе, в идеале включив подходящий разделитель, чтобы можно было различать объединённые значения. Например, в Oracle вы можете отправить ввод:
' UNION SELECT username || '~' || password FROM users--
Здесь используется последовательность двух вертикальных черт (или пайпов) ||
являющаяся оператором конкатенации строк в Oracle. Внедрённый SQL запрос объединит значения полей username
и password
, разделённые символом ~
.
Результаты запроса позволят вам прочитать имена всех пользователей и пароли, например:
...
administrator~s3cure
wiener~peter
carlos~montoya
...
Обратите внимание, что разные базы данных используют разный синтаксис для выполнения конкатенации строк. Дополнительные сведения можно узнать в Шпаргалке по SQL-инъекциям