Что такое EXTRACTVALUE и при чём тут SQL-инъекция?

Строка %') AND EXTRACTVALUE(3873,CONCAT(0x7e,((SELECT (ELT(3873=3873,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции для СУБД MySQL. Она предназначена для извлечения данных из базы через вывод сообщения об ошибке. В данной статье мы детально разберём, как работает этот запрос, какие функции задействованы и как защититься от подобных атак.

Функция EXTRACTVALUE: назначение и синтаксис

EXTRACTVALUE — это встроенная функция MySQL (а также Oracle), предназначенная для извлечения значения из XML-документа с помощью XPath-выражения. Синтаксис:

EXTRACTVALUE(XMLType_instance, XPath_expression)

Функция принимает два аргумента: экземпляр типа XML и выражение XPath. Возвращает скалярное значение узла, соответствующего XPath. Результат должен быть единственным узлом — текстовым, атрибутом или элементом. Если элемент содержит несколько текстовых узлов, возвращается ошибка.

Однако злоумышленники нашли способ использовать эту функцию для вывода произвольных данных через сообщения об ошибках. Если XPath-выражение некорректно, MySQL генерирует ошибку, в тексте которой может содержаться переданное значение.

Разбор вредоносного запроса

Рассмотрим строку по частям:

  • %') — закрывает предыдущее выражение в уязвимом запросе. Символ % часто используется в LIKE-запросах, а ') закрывает скобку и кавычку, завершая оригинальное условие.
  • AND EXTRACTVALUE(3873,CONCAT(0x7e,((SELECT (ELT(3873=3873,1)))),0x7e)) — внедряемая конструкция. Число 3873 — произвольный идентификатор, не влияющий на логику, но необходимый для синтаксиса. Второй аргумент — XPath-выражение, формируемое через CONCAT.
  • -- - — комментарий, который игнорирует остаток оригинального запроса.

Функция CONCAT и тильда (0x7e)

CONCAT объединяет строки. В данном случае к результату подзапроса добавляются символы ~ (0x7e в шестнадцатеричном виде) с обеих сторон. Тильда используется как маркер, чтобы облегчить поиск выводимых данных в сообщении об ошибке.

Подзапрос с ELT и условием 3873=3873

ELT(N, str1, str2, ...) возвращает N-й элемент из списка строк. В нашем случае ELT(3873=3873,1) — условие 3873=3873 всегда истинно, что даёт 1. Значит, ELT вернёт первый элемент — число 1. Это простейший пример; в реальных атаках вместо 1 может быть подзапрос, извлекающий данные (например, имя таблицы, хеш пароля).

Таким образом, CONCAT сформирует строку вида ~1~. Затем EXTRACTVALUE попытается интерпретировать её как XPath. Поскольку ~1~ не является корректным XPath, MySQL выдаст ошибку, в тексте которой будет фигурировать переданная строка. Злоумышленник, анализируя сообщение об ошибке, может получить интересующие его данные.

Зачем нужна такая инъекция?

Error-based SQL-инъекции позволяют извлекать информацию из базы данных, когда прямой вывод результатов (union-based) невозможен. Они эксплуатируют недостаточную фильтрацию пользовательского ввода и вывод ошибок СУБД на страницу. В случае с EXTRACTVALUE атакующий может получить имена таблиц, колонок, логины, пароли и другую конфиденциальную информацию.

Как защититься от SQL-инъекций через EXTRACTVALUE?

  1. Используйте подготовленные выражения (prepared statements). Параметризация запросов — самый надёжный способ предотвратить инъекции. Данные передаются отдельно от SQL-кода и не интерпретируются как часть запроса.
  2. Экранируйте пользовательский ввод. Если по каким-то причинам нельзя использовать подготовленные выражения, применяйте функции экранирования, такие как mysqli_real_escape_string.
  3. Ограничьте права пользователя БД. Учётная запись, используемая веб-приложением, должна иметь минимально необходимые привилегии. Не давайте доступ к системным таблицам без надобности.
  4. Отключите вывод ошибок СУБД на продакшене. Сообщения об ошибках не должны попадать в браузер пользователя. Логируйте их, но не показывайте.
  5. Регулярно обновляйте СУБД и фреймворки. Уязвимости в самом MySQL или в библиотеках могут усугубить ситуацию.
  6. Используйте WAF (Web Application Firewall). Современные WAF могут обнаруживать и блокировать попытки SQL-инъекций по сигнатурам, включая конструкции с EXTRACTVALUE.

Заключение

Запрос %') AND EXTRACTVALUE(3873,CONCAT(0x7e,((SELECT (ELT(3873=3873,1)))),0x7e))-- - — это типичный пример эксплуатации уязвимости error-based SQL-инъекции в MySQL. Понимание механизма работы таких атак помогает разработчикам и администраторам правильно выстраивать защиту. Главный вывод: никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.

Источники