Введение
SQL-инъекции остаются одной из самых опасных уязвимостей веб-приложений. Среди множества техник особое место занимает инъекция на основе ошибок (error-based SQL injection) с использованием функции ExtractValue в СУБД MySQL. Запрос, который вы видите в заголовке, — это классический пример такой атаки. Давайте разберём, что он означает, как работает и почему это важно для безопасности.
Что такое ExtractValue?
ExtractValue() — встроенная функция MySQL, предназначенная для извлечения значения из XML-строки по заданному пути XPath. Синтаксис: ExtractValue(XML_document, XPath_expression). Например, SELECT ExtractValue('<a><b>текст</b></a>', '/a/b') вернёт «текст». Казалось бы, безобидная функция. Однако злоумышленники научились использовать её для вывода произвольных данных через сообщения об ошибках.
Механизм атаки
Если в XPath-выражении допустить синтаксическую ошибку, MySQL генерирует сообщение об ошибке, которое включает фрагмент переданного XPath. Это позволяет внедрить в XPath результат подзапроса и увидеть его в тексте ошибки. Именно это и происходит в запросе %" AND EXTRACTVALUE(9811,CONCAT(0x7e,((SELECT (ELT(9811=9811,1)))),0x7e))-- -.
Разбор запроса
Рассмотрим по частям:
%"— попытка закрыть предыдущую строку и кавычку, чтобы внедрить свой код.AND EXTRACTVALUE(9811, CONCAT(...))— вызов функции с первым аргументом 9811 (произвольное число, не являющееся корректным XML) и вторым аргументом — конкатенацией тильды (0x7e), результата подзапроса и ещё одной тильды.SELECT (ELT(9811=9811,1))— подзапрос, возвращающий 1, если условие истинно. В данном случае 9811=9811 всегда истина, поэтому вернётся 1. Это простейшая проверка возможности выполнения подзапросов.-- -— комментарий, отсекающий остаток оригинального запроса.
При выполнении MySQL попытается извлечь XPath из строки, начинающейся с тильды, что вызовет ошибку вида: XPATH syntax error: '~1~'. В сообщении об ошибке мы увидим результат подзапроса — единицу. Злоумышленник может заменить ELT(9811=9811,1) на любой другой подзапрос, например, (SELECT version()), и получить версию СУБД, имена таблиц, хеши паролей и другие конфиденциальные данные.
Важно: подобные инъекции возможны только при отсутствии должной фильтрации входных данных и выводе ошибок СУБД на экран.
Практические примеры
В реальных атаках злоумышленники используют вариации этого запроса для извлечения информации посимвольно или целыми строками. Например, чтобы получить имя текущей базы данных, можно применить:
' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e))-- -
Если приложение уязвимо, в ответе появится ошибка с названием базы данных. Аналогично извлекаются таблицы, столбцы и записи.
Ошибка 1222
Иногда вместо ожидаемой ошибки XPath можно получить ERROR 1222 (21000): The used SELECT statements have a different number of columns. Это происходит, когда инъекция выполняется через UNION SELECT и количество столбцов в оригинальном запросе не совпадает с внедряемым. В контексте ExtractValue такая ошибка возникает, если злоумышленник неправильно подобрал количество столбцов. Это также может быть сигналом для атакующего о структуре запроса.
Как защититься?
Основной метод — использование параметризованных запросов (prepared statements). Они гарантируют, что пользовательский ввод никогда не будет интерпретирован как SQL-код. Дополнительные меры:
- Отключите вывод ошибок СУБД в production-окружении. Ошибки должны логироваться, а не показываться пользователю.
- Применяйте принцип наименьших привилегий для учётной записи базы данных: не давайте ей прав на чтение системных таблиц без необходимости.
- Используйте WAF (Web Application Firewall) для фильтрации подозрительных запросов.
- Регулярно обновляйте MySQL и веб-приложения, чтобы закрыть известные уязвимости.
- Проводите аудит кода и пентесты.
Заключение
SQL-инъекция с ExtractValue — яркий пример того, как безобидная функция может стать инструментом атаки. Понимание её механизма помогает разработчикам и специалистам по безопасности лучше защищать свои системы. Помните: безопасность — это процесс, а не одноразовое действие.
Комментарии
—Войдите, чтобы оставить комментарий