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

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

Злоумышленники используют функцию для принудительного вывода данных через сообщения об ошибках. Например, внедряя в уязвимый параметр конструкцию вида AND EXTRACTVALUE(7341,CONCAT(0x7e,(SELECT ...),0x7e)), атакующий заставляет СУБД вернуть результат подзапроса в тексте ошибки. Это позволяет посимвольно извлекать содержимое базы данных, даже если прямой вывод данных заблокирован.

Разбор конкретной полезной нагрузки

Рассмотрим запрос: %') AND EXTRACTVALUE(7341,CONCAT(0x7e,((SELECT (ELT(7341=7341,1)))),0x7e))-- -. Это классический пример error-based SQL-инъекции, адаптированный под MySQL. Разберём его по частям.

  • %') — попытка закрыть предыдущее строковое выражение и скобку, чтобы внедрить собственный код. Символ % часто используется как подстановочный знак в LIKE-запросах, но здесь он часть строки, которую нужно разорвать.
  • AND EXTRACTVALUE(...) — логическое условие, которое выполняется, если предыдущая часть запроса истинна. Функция EXTRACTVALUE вызывается с двумя аргументами: первый — произвольное число (7341), второй — XPath-выражение, сформированное через CONCAT.
  • CONCAT(0x7e, ((SELECT (ELT(7341=7341,1)))), 0x7e) — конкатенация тильды (0x7e — шестнадцатеричный код символа ~), результата подзапроса и ещё одной тильды. Тильды служат маркерами, чтобы облегчить извлечение данных из сообщения об ошибке.
  • SELECT (ELT(7341=7341,1)) — подзапрос, возвращающий 1, если условие 7341=7341 истинно (а это всегда так). ELT — функция, возвращающая N-й элемент из списка. Здесь она возвращает 1. В реальной атаке вместо этого подзапроса мог бы быть, например, SELECT version() или SELECT table_name FROM information_schema.tables.
  • -- - — комментарий, отсекающий оставшуюся часть оригинального SQL-запроса.

При выполнении такого запроса MySQL попытается интерпретировать строку ~1~ как XPath. Поскольку это невалидный XPath, возникнет ошибка: XPATH syntax error: '~1~'. В этом сообщении и окажется результат подзапроса — в данном случае «1». Если бы вместо ELT стоял вызов, возвращающий имя пользователя или версию СУБД, эти данные утекли бы в ответе сервера.

Почему EXTRACTVALUE эффективен для error-based инъекций?

Функция EXTRACTVALUE часто используется в error-based SQL-инъекциях по нескольким причинам:

  1. Вывод данных в ошибке. Сообщение об ошибке XPATH содержит переданную строку, что позволяет злоумышленнику видеть результаты подзапросов.
  2. Обход фильтров. Многие системы защиты фильтруют ключевые слова вроде UNION SELECT, но редко блокируют EXTRACTVALUE или подобные функции.
  3. Простота использования. Не требуется угадывать количество столбцов, как в UNION-инъекциях. Достаточно внедрить функцию в существующий запрос.
  4. Работа в слепую. Даже если приложение не выводит ошибки напрямую, их можно использовать в blind-инъекциях, анализируя поведение сервера (например, время ответа).

Аналогичными возможностями обладают функции UPDATEXML и GTID_SUBSET, но EXTRACTVALUE остаётся классикой.

Примеры реальных атак

В отчётах по пентестам часто описывают эксплуатацию error-based SQL-инъекций через EXTRACTVALUE. Например, на уязвимом параметре id=1' можно внедрить:

1' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT database()),0x7e))-- -

В ответе сервера появится ошибка вида XPATH syntax error: '~имя_базы~'. Далее можно извлекать таблицы, столбцы и данные, используя подзапросы с LIMIT и OFFSET.

Важно отметить, что EXTRACTVALUE работает только в том случае, если в запросе есть XML-документ. Однако MySQL позволяет передавать в качестве первого аргумента любое значение, включая число, — это не вызывает ошибки до момента разбора XPath. Именно на этом строится эксплойт.

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

Основной метод защиты — использование параметризованных запросов (prepared statements). Они разделяют код SQL и данные, поэтому внедрение произвольных выражений становится невозможным. Дополнительные меры:

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

Также рекомендуется регулярно обновлять СУБД: в новых версиях MySQL некоторые функции могут быть удалены или изменены, что снижает риск. Например, EXTRACTVALUE была объявлена устаревшей в MySQL 5.7 и удалена в MySQL 8.0.

Заключение

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

Источники