SQL-инъекции: UNION атаки

Источник: «SQL injection UNION attacks»
Когда приложение уязвимо для SQL-инъекций и результат запроса возвращаются в ответах приложения, можно использовать ключевое слово UNION для извлечения данных из других таблиц базы данных. Это приводит к 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. В худшем случае ответ может быть неотличим от ответа, вызванного неправильным количеством нулей, что делает этот метод определения количества столбцов неэффективным.

Примечание

Дополнительная информация о синтаксисе специфичном для основных (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 запросом, и нашли, какие столбцы могут содержать строковые данные, вы можете получить интересные данные.

Предположим, что:

В этой ситуации вы можете получить содержимое таблицы 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-инъекциям

Дополнительные материалы

Предыдущая Статья

SQLi: Шпаргалка по SQL-инъекциям

Следующая Статья

Клонирование readonly свойств в PHP 8.3