Атаки SQL-инъекции с использованием UNION (UNION-based SQLi)
Когда приложение уязвимо к SQL-инъекции и результаты запроса возвращаются в ответах приложения, вы можете использовать ключевое слово UNION, чтобы извлекать данные из других таблиц в базе данных. Это обычно называется атакой SQL-инъекции с использованием UNION.
Ключевое слово UNION позволяет выполнить один или несколько дополнительных запросов SELECT и добавить их результаты к исходному запросу. Например:
SELECT a, b FROM table1 UNION SELECT c, d FROM table2Этот SQL-запрос возвращает один набор результатов с двумя столбцами, содержащий значения из столбцов a и b таблицы table1 и столбцов c и d таблицы table2.
Для работы запроса UNION должны быть выполнены два ключевых требования:
Отдельные запросы должны возвращать одинаковое количество столбцов.
Типы данных в каждом столбце должны быть совместимы между отдельными запросами.
Чтобы провести атаку SQL-инъекции с использованием UNION, убедитесь, что ваша атака соответствует этим двум требованиям. Обычно это включает выяснение:
Сколько столбцов возвращает исходный запрос.
Какие столбцы, возвращаемые исходным запросом, имеют подходящий тип данных для размещения результатов из внедрённого запроса.
Определение требуемого количества столбцов
При выполнении атаки SQL-инъекции с использованием UNION есть два эффективных метода, чтобы определить, сколько столбцов возвращается исходным запросом. Один метод включает внедрение серии предложений ORDER BY с увеличением указанного индекса столбца до тех пор, пока не возникнет ошибка. Например, если точка инъекции — это заключённая в кавычки строка внутри WHERE исходного запроса, вы бы отправили:
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
etc.Эта серия полезных нагрузок модифицирует исходный запрос, упорядочивая результаты по разным столбцам набора результатов. Столбец в ORDER BY можно указывать по его индексу, поэтому вам не нужно знать имена столбцов. Когда указанный индекс столбца превышает количество фактических столбцов в наборе результатов, база данных возвращает ошибку, например:
Приложение может вернуть текст ошибки базы данных в своём HTTP-ответе, но также может выдать общий ответ об ошибке. В других случаях оно может просто вовсе не вернуть результатов. В любом случае, пока вы способны зафиксировать различие в ответе, вы можете вывести, сколько столбцов возвращает запрос.
Второй метод включает отправку серии полезных нагрузок UNION SELECT с разным количеством значений NULL:
Если количество NULL не совпадает с количеством столбцов, база данных возвращает ошибку, например:
Мы используем NULL как значения, возвращаемые внедрённым запросом SELECT, потому что типы данных в каждом столбце должны быть совместимы между исходным и внедрённым запросами. NULL приводим к каждому распространённому типу данных, поэтому он повышает шанс успеха полезной нагрузки при верном числе столбцов.
Как и в технике ORDER BY, приложение может вернуть текст ошибки базы в HTTP-ответе, но может вернуть общий ответ об ошибке или просто не вернуть результатов. Когда количество NULL совпадает с числом столбцов, база данных возвращает дополнительную строку в наборе результатов, содержащую значения NULL в каждом столбце. Эффект в HTTP-ответе зависит от кода приложения. Если повезёт, вы увидите дополнительный контент в ответе, например ещё одну строку HTML-таблицы. В противном случае значения NULL могут вызвать другую ошибку, например NullPointerException. В худшем случае ответ может выглядеть так же, как и при неправильном количестве NULL, что сделает этот метод неэффективным.
Синтаксис, зависящий от СУБД
В Oracle каждый запрос SELECT должен использовать ключевое слово FROM и указывать валидную таблицу. В Oracle есть встроенная таблица dual, которую можно использовать для этой цели. Поэтому внедрённые запросы в Oracle должны выглядеть так:
В описанных полезных нагрузках используется последовательность комментария из двух дефисов --, чтобы закомментировать остаток исходного запроса после точки инъекции. В MySQL после двух дефисов должен следовать пробел. В качестве альтернативы можно использовать символ решётки # для обозначения комментария. Подробности синтаксиса для конкретных СУБД см. в разделе SQL injection cheat sheet.
Поиск столбцов с подходящим типом данных
Атака SQL-инъекции с использованием UNION позволяет извлекать результаты из внедрённого запроса. Интересные для вас данные обычно имеют строковую форму. Это означает, что вам нужно найти один или несколько столбцов в исходных результатах, тип данных которых является строковым или совместим со строковыми данными.
После того как вы определили требуемое количество столбцов, вы можете проверить каждый столбец на способность содержать строковые данные. Отправьте серию полезных нагрузок UNION SELECT, помещающих строковое значение по очереди в каждый столбец. Например, если запрос возвращает четыре столбца, вы бы отправили:
Если тип данных столбца несовместим со строковыми данными, внедрённый запрос вызовет ошибку базы данных, например:
Если ошибки не возникает, а ответ приложения содержит дополнительный контент с внедрённым строковым значением, значит соответствующий столбец подходит для извлечения строковых данных.
Использование атаки SQL-инъекции с UNION для извлечения интересных данных
Когда вы определили количество столбцов, возвращаемых исходным запросом, и выяснили, какие столбцы могут содержать строковые данные, вы готовы извлекать интересующие данные.
Предположим, что:
Исходный запрос возвращает два столбца, оба могут содержать строковые данные.
Точка инъекции — это строка в кавычках внутри
WHERE.В базе есть таблица
usersсо столбцамиusernameиpassword.
В этом примере вы можете извлечь содержимое таблицы users, отправив следующий ввод:
Чтобы выполнить эту атаку, вам нужно знать, что существует таблица users с двумя столбцами username и password. Без этой информации вам пришлось бы угадывать имена таблиц и столбцов. Все современные базы данных предоставляют способы изучать структуру базы и определять, какие таблицы и столбцы она содержит.
Извлечение нескольких значений в одном столбце
В некоторых случаях запрос из предыдущего примера может возвращать только один столбец.
Вы можете извлекать несколько значений внутри этого одного столбца, конкатенируя их. Можно включить разделитель, чтобы различать объединённые значения. Например, в Oracle вы могли бы отправить такой ввод:
Здесь используется последовательность из двух вертикальных черт ||, которая является оператором конкатенации строк в Oracle. Внедрённый запрос объединяет значения полей username и password, разделённые символом ~.
Результаты запроса содержат все имена пользователей и пароли, например:
Разные базы данных используют разный синтаксис для конкатенации строк. Подробности смотрите в SQL injection cheat sheet.
Last updated