Введение в проблему

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

Что такое ExtractValue и XPATH-инъекция

EXTRACTVALUE — это встроенная функция MySQL, предназначенная для извлечения значения из XML-документа по заданному XPath-выражению. Синтаксис: EXTRACTVALUE(xml_frag, xpath_expr). Если XPath-выражение некорректно, MySQL генерирует ошибку, в тексте которой может отображаться часть переданного выражения. Это и стало основой для error-based SQL-инъекций через XPATH.

Аналогичная функция — UPDATEXML — также подвержена этой уязвимости. Злоумышленник может внедрить в XPath специальные символы (например, ~), чтобы вызвать ошибку и вывести в ней результат подзапроса.

Разбор конкретного payload

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

  • ")) — закрывает предыдущие кавычки и скобки в оригинальном SQL-запросе, чтобы внедрить свой код.
  • OR EXTRACTVALUE(9210,CONCAT(0x7e,((SELECT (ELT(9210=9210,1)))),0x7e)) — внедряемая конструкция. Она вызывает функцию EXTRACTVALUE с произвольными аргументами.
  • -- - — комментарий, обрезающий остаток оригинального запроса.

Внутри EXTRACTVALUE используется CONCAT, который объединяет символ ~ (0x7e), результат подзапроса и снова ~. Подзапрос SELECT (ELT(9210=9210,1)) — это упрощённый пример. ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь 9210=9210 — всегда истина (1), поэтому ELT(1,1) вернёт 1. В реальной атаке вместо этого подзапроса внедряется запрос к системным таблицам, например, SELECT version() или SELECT table_name FROM information_schema.tables.

Функция EXTRACTVALUE ожидает первым аргументом XML-документ. Число 9210 не является валидным XML, поэтому MySQL попытается его обработать и выдаст ошибку, в тексте которой будет содержаться переданное XPath-выражение, включая результат подзапроса. Таким образом, злоумышленник может читать данные из базы.

Почему это работает: механизм ошибки

MySQL при вызове EXTRACTVALUE(9210, ...) пытается интерпретировать первый аргумент как XML. Поскольку это не XML, возникает ошибка вида: XPATH syntax error: '~1~'. В этой ошибке отображается второй аргумент — XPath-выражение, которое мы сформировали. Если вместо 1 подставить, например, SELECT database(), то в ошибке появится имя текущей базы данных. Это и есть эксплойт.

Важно: начиная с MySQL 5.7.9 и в MariaDB, функция EXTRACTVALUE была удалена или изменена, что делает этот вектор атаки неработоспособным на новых версиях. Однако многие устаревшие системы всё ещё уязвимы.

Пошаговый пример эксплуатации

  1. Злоумышленник находит параметр, уязвимый к SQL-инъекции, например, ?id=1.
  2. Внедряет payload: 1")) OR EXTRACTVALUE(1,CONCAT(0x7e,(SELECT version()),0x7e))-- -.
  3. Сервер выполняет запрос, и в ответе возвращается ошибка с версией MySQL.
  4. Далее можно извлекать имена таблиц, столбцов и данные, используя подзапросы с LIMIT и смещениями.

В нашем случае с ELT(9210=9210,1) это демонстрационный пример, показывающий, что подзапрос может быть любым. Число 9210 — просто случайный идентификатор, не несущий смысла.

Меры защиты

Чтобы предотвратить эксплуатацию подобных уязвимостей, необходимо:

  • Использовать подготовленные выражения (prepared statements) с параметризацией. Это самый надёжный способ.
  • Проводить строгую валидацию всех входных данных, особенно тех, что попадают в SQL-запросы.
  • Обновить MySQL до версии 5.7.9+ или использовать MariaDB, где EXTRACTVALUE удалена.
  • Отключить вывод подробных ошибок СУБД на продакшене, чтобы злоумышленник не мог получить данные через сообщения об ошибках.
  • Использовать WAF (Web Application Firewall) для фильтрации подозрительных запросов.

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

Заключение

Payload ")) OR EXTRACTVALUE(9210,CONCAT(0x7e,((SELECT (ELT(9210=9210,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции через XPATH. Он демонстрирует, как небрежная обработка пользовательского ввода может привести к утечке данных. Понимание механизма работы таких атак помогает разработчикам и администраторам своевременно закрывать уязвимости. Всегда используйте параметризованные запросы и следите за актуальностью версий СУБД.

Источники