Что такое error-based SQL-инъекция через ExtractValue

SQL-инъекция остаётся одной из самых опасных уязвимостей веб-приложений и стабильно входит в топ OWASP. Среди множества техник особое место занимает error-based SQL-инъекция, при которой злоумышленник извлекает данные через сообщения об ошибках базы данных. Один из классических приёмов для MySQL — использование функции ExtractValue().

Функция ExtractValue(XML_document, XPath_expression) предназначена для извлечения значений из XML-документа по указанному XPath-выражению. Если XPath-выражение синтаксически некорректно, MySQL возвращает ошибку XPATH syntax error с фрагментом переданного выражения. Именно это свойство эксплуатируется: злоумышленник подставляет в XPath результат подзапроса, и СУБД сама «показывает» данные в тексте ошибки.

Разбор конкретного запроса

Рассмотрим запрос из заголовка:

")) AND EXTRACTVALUE(2260,CONCAT(0x7e,((SELECT (ELT(2260=2260,1)))),0x7e))-- -

Он представляет собой фрагмент, который внедряется в уязвимый SQL-запрос. Разберём его по частям.

Синтаксис и контекст внедрения

  • ")) — закрывающие кавычка и скобки. Они «выравнивают» исходный SQL-запрос, чтобы внедряемый код стал его продолжением. Точный набор символов зависит от того, как построен оригинальный запрос.
  • AND — логический оператор, присоединяющий условие к WHERE-части.
  • EXTRACTVALUE(2260, CONCAT(...)) — вызов уязвимой функции. Первый аргумент — произвольный XML-документ (здесь просто число 2260, которое MySQL преобразует в строку).
  • -- - — комментарий, обрезающий остаток оригинального запроса. Пробел после двух дефисов обязателен для MySQL.

Зачем нужен CONCAT и 0x7e

Функция CONCAT() склеивает несколько строк. Константа 0x7e — это шестнадцатеричное представление символа тильды ~. Тильда используется как маркер-ограничитель: она отделяет полезные данные от остального текста в сообщении об ошибке, чтобы их было легко найти. Итоговая XPath-строка принимает вид ~<данные>~.

Символ ~ недопустим в начале XPath-выражения, поэтому MySQL гарантированно выдаст ошибку вида:

ERROR 1105 (HY000): XPATH syntax error: ':~1~'

В этом сообщении между тильдами окажется результат подзапроса — именно то, что нужно атакующему.

Подзапрос с ELT(2260=2260,1)

Внутри CONCAT находится подзапрос:

(SELECT (ELT(2260=2260,1)))

Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь N — это результат сравнения 2260=2260, которое всегда истинно и в числовом контексте даёт 1. Следовательно, ELT(1, 1) вернёт строку '1'. В учебном примере это просто демонстрация работы конструкции: на месте 1 мог бы стоять любой другой подзапрос, например (SELECT version()) или (SELECT password FROM users LIMIT 1).

Таким образом, запрос проверяет, что инъекция выполняется, и показывает, как через ошибку можно вытащить произвольные данные.

Почему это работает: особенности MySQL

Функция ExtractValue появилась в MySQL 5.1 и доступна во всех последующих версиях, включая 5.7 и 8.0. При передаче некорректного XPath-выражения СУБД возвращает ошибку, содержащую до 64 символов этого выражения. Этого достаточно для посимвольного извлечения данных, хотя для длинных строк приходится использовать SUBSTRING и смещения.

Аналогичным образом работает функция UpdateXML(), которая также генерирует XPATH-ошибку. Обе функции часто используются в автоматизированных инструментах, например в sqlmap, для ускорения эксплуатации error-based инъекций.

Как защититься от таких атак

Главный принцип — никогда не конкатенировать пользовательский ввод в SQL-запросы. Вот основные меры:

  • Параметризованные запросы (prepared statements). Это самый надёжный способ. Данные передаются отдельно от кода, и СУБД не интерпретирует их как SQL.
  • Хранимые процедуры. При правильной реализации также исключают инъекции.
  • Экранирование специальных символов. Например, функция mysqli_real_escape_string() в PHP. Но это менее надёжно, чем параметризация.
  • Ограничение прав пользователя БД. Приложение должно работать под учётной записью с минимально необходимыми привилегиями (никаких FILE, PROCESS и т.п.).
  • Отключение вывода ошибок БД в продакшене. Сообщения об ошибках не должны попадать в ответы сервера.
  • WAF. Веб-прикладной экран может блокировать подозрительные конструкции, но не является панацеей.

Также рекомендуется регулярно проводить аудит кода и сканирование уязвимостей, а разработчиков обучать безопасной работе с SQL.

Итог

Запрос ")) AND EXTRACTVALUE(2260,CONCAT(0x7e,((SELECT (ELT(2260=2260,1)))),0x7e))-- - — это учебный пример error-based SQL-инъекции через функцию ExtractValue в MySQL. Он показывает, как с помощью тильды-ограничителя и подзапроса можно заставить базу данных выдать данные в тексте ошибки. Понимание этой техники необходимо как специалистам по безопасности, так и разработчикам, чтобы своевременно закрывать подобные уязвимости с помощью параметризованных запросов и других мер защиты.

Источники