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

Функция EXTRACTVALUE() в MySQL предназначена для работы с XML-данными. Она принимает два строковых аргумента: фрагмент XML-разметки и XPath-выражение (локатор). Функция возвращает текст (CDATA) первого текстового узла, который является дочерним для элемента или элементов, соответствующих XPath-выражению. Например, запрос SELECT EXTRACTVALUE('<a>текст</a>', '/a') вернёт строку «текст».

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

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

Рассмотрим строку, которая стала предметом этого разбора:

')) AND EXTRACTVALUE(8636,CONCAT(0x7e,((SELECT (ELT(8636=8636,1)))),0x7e))-- -

Это типичная полезная нагрузка (payload) для проверки наличия error-based SQL-инъекции. Разберём её по частям:

  • ')) — закрывающие кавычка и скобка. Они нужны, чтобы «закрыть» оригинальный SQL-запрос, в который внедряется код. Если приложение подставляет пользовательский ввод внутрь запроса с кавычками и скобками, эти символы позволяют выйти за пределы строкового литерала.
  • AND EXTRACTVALUE(8636, ...) — добавляет условие в запрос. Число 8636 здесь — произвольный идентификатор, не влияющий на логику, но необходимый для синтаксиса функции.
  • CONCAT(0x7e, ((SELECT (ELT(8636=8636,1)))), 0x7e) — формирует строку для XPath. 0x7e — это шестнадцатеричный код символа «~» (тильда). Внутри выполняется подзапрос SELECT ELT(8636=8636,1). Функция ELT возвращает N-й элемент из списка; условие 8636=8636 всегда истинно, поэтому возвращается 1. Фактически это заглушка, демонстрирующая возможность выполнения подзапросов.
  • -- - — комментарий, который отсекает оставшуюся часть оригинального SQL-запроса, чтобы не возникло синтаксической ошибки.

Если запрос уязвим, MySQL попытается вычислить EXTRACTVALUE с аргументом, начинающимся с тильды, что не является корректным XPath. В результате возникнет ошибка вида XPATH syntax error: '~1~'. Именно этот текст, содержащий результат подзапроса, увидит атакующий в ответе сервера.

Почему это работает: механизм error-based инъекции

Error-based SQL-инъекция — это метод, при котором злоумышленник заставляет базу данных выдать конфиденциальные сведения прямо в сообщении об ошибке. В MySQL для этого traditionally использовались функции EXTRACTVALUE() и UPDATEXML(). Обе они при некорректном XPath возвращают ошибку, включающую переданную строку.

Атакующий может подставить в CONCAT не просто число, а, например, результат подзапроса (SELECT version()) или (SELECT password FROM users LIMIT 1). Тогда в тексте ошибки отобразится версия СУБД или хеш пароля. Поскольку длина сообщения ограничена (около 32 символов), данные извлекаются посимвольно с помощью функций SUBSTRING, MID или LIMIT.

Важно отметить, что начиная с MySQL 5.7.9 функция EXTRACTVALUE была объявлена устаревшей, а в MySQL 8.0 удалена. Однако множество legacy-систем до сих пор работают на старых версиях, что делает эту технику актуальной.

Как распознать попытку эксплуатации

В логах веб-сервера или WAF можно заметить характерные признаки:

  • Наличие в параметрах запросов функций EXTRACTVALUE, UPDATEXML, CONCAT с шестнадцатеричными последовательностями (0x7e).
  • Комбинации закрывающих кавычек и скобок: ')), ")), ') и т.п.
  • Использование комментариев -- -, #, /* */ для обрыва запроса.
  • Подзапросы с ELT, IF, CASE, направленные на извлечение метаданных.

Если вы обнаружили такие строки в логах, это сигнал о попытке взлома. Необходимо срочно проверить код приложения на наличие уязвимостей.

Меры защиты от error-based SQL-инъекций

Основной способ предотвращения — использование параметризованных запросов (prepared statements). При этом пользовательские данные передаются отдельно от SQL-кода и не могут изменить структуру запроса. Даже если злоумышленник введёт ')) AND EXTRACTVALUE(...)-- -, это будет воспринято как обычная строка.

Дополнительные меры:

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

Заключение

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

Источники