Введение

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

Источники