Что такое EXTRACTVALUE и при чём здесь SQL-инъекции?

Функция EXTRACTVALUE в MySQL предназначена для извлечения значения из XML-документа по заданному XPath-выражению. Однако из-за особенностей обработки ошибок она стала популярным инструментом для проведения error-based SQL-инъекций. Злоумышленники заставляют базу данных выдать сообщение об ошибке, содержащее конфиденциальные данные, например, имена таблиц, столбцов или хэши паролей.

В запросе пользователя: %"))) AND EXTRACTVALUE(7484,CONCAT(0x7e,((SELECT (ELT(7484=7484,1)))),0x7e))-- - — как раз демонстрируется классический пример такой инъекции. Давайте разберём его по частям.

Анатомия инъекции

Строка состоит из нескольких компонентов:

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

Цель — заставить MySQL выполнить подзапрос и вывести его результат в сообщении об ошибке.

Как работает EXTRACTVALUE в контексте атаки

Синтаксис функции: EXTRACTVALUE(XML_document, XPath_expression). Если XPath-выражение некорректно, MySQL генерирует ошибку вида: XPATH syntax error: '...'. В эту ошибку попадает часть переданного XPath. Злоумышленник конструирует XPath так, чтобы в него попали данные из базы.

В нашем примере вторым аргументом идёт CONCAT(0x7e,((SELECT (ELT(7484=7484,1)))),0x7e). 0x7e — это тильда (~), используемая как маркер начала и конца выводимых данных. ELT(7484=7484,1) возвращает строку '1', так как условие 7484=7484 истинно. Фактически это простейший тест: если инъекция работает, в ошибке появится ~1~.

Почему используется ELT?

ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В данном случае ELT(7484=7484,1) вернёт '1', потому что условие истинно (1). Это позволяет создавать условные конструкции: если условие ложно, ELT вернёт NULL, и ошибка может не содержать данных. Такой подход часто применяется для слепых инъекций, но в error-based он служит для проверки работоспособности.

Пошаговый разбор примера

  1. Закрытие предыдущих конструкций: %"))) — предполагается, что исходный запрос содержал незакрытые кавычки и скобки. Символ % может быть частью URL-кодирования.
  2. Добавление условия AND: чтобы инъекция сработала, нужно, чтобы левая часть выражения была истинной. Если исходный запрос возвращает результаты, добавление AND ... не нарушит логику, но выполнит внедрённую функцию.
  3. Вызов EXTRACTVALUE: первый аргумент — произвольное число (7484), второй — сконкатенированная строка с тильдами и подзапросом.
  4. Подзапрос: (SELECT (ELT(7484=7484,1))) — возвращает '1'.
  5. Комментарий: -- - отсекает всё после инъекции, чтобы синтаксис остался корректным.

В результате MySQL выполнит функцию и выдаст ошибку: XPATH syntax error: '~1~'. Это подтверждает, что инъекция возможна. Далее злоумышленник заменяет ELT(7484=7484,1) на подзапрос, извлекающий нужные данные, например: (SELECT table_name FROM information_schema.tables LIMIT 0,1).

Реальные примеры извлечения данных

Для получения имён таблиц используется запрос к information_schema.tables. Например:

AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1), 0x7e))

В ошибке появится имя первой таблицы. Аналогично можно извлечь столбцы, логины и пароли.

Более сложные варианты используют CONCAT_WS, GROUP_CONCAT и другие функции для объединения данных в одну строку.

Защита от error-based SQL-инъекций

Основные меры:

  • Параметризованные запросы (prepared statements): самый надёжный способ, при котором данные не попадают в текст SQL.
  • Экранирование специальных символов: но это менее надёжно, чем параметризация.
  • Отключение вывода ошибок СУБД на продакшене: чтобы злоумышленник не видел сообщения с данными.
  • Использование ORM: современные ORM обычно используют параметризацию.
  • Регулярные аудиты безопасности и сканеры уязвимостей.

Важно понимать, что EXTRACTVALUE — не единственная функция для error-based инъекций. Также используются UPDATEXML, GTID_SUBSET, EXP и другие. Однако EXTRACTVALUE и UPDATEXML наиболее популярны из-за явного вывода данных в тексте ошибки.

Заключение

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

Источники