Что такое EXTRACTVALUE?

Функция EXTRACTVALUE — это встроенная функция MySQL (и некоторых других СУБД), предназначенная для извлечения данных из XML-документов с помощью языка XPath. Она принимает два строковых аргумента: фрагмент XML-разметки и выражение XPath (локатор). Функция возвращает текст (CDATA) первого текстового узла, который является дочерним по отношению к элементу или элементам, соответствующим XPath-выражению.

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

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

Рассмотрим запрос, который часто встречается в отчётах об уязвимостях и на форумах пентестеров:

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

Этот фрагмент — классический пример внедрения в параметр, который передаётся в SQL-запрос. Давайте разберём его по частям:

  • ) — закрывает ранее открытую скобку в исходном запросе, чтобы внедрение было синтаксически корректным.
  • AND — логический оператор, присоединяющий наше условие к оригинальному запросу.
  • EXTRACTVALUE(6668, CONCAT(...)) — вызов функции EXTRACTVALUE. Первый аргумент — произвольное число (6668), которое не является корректным XML. Это гарантирует, что функция вызовет ошибку.
  • CONCAT(0x7e, ((SELECT (ELT(6668=6668,1)))), 0x7e) — конкатенация символа тильды (~, код 0x7e), результата подзапроса и ещё одной тильды. Тильды используются как маркеры, чтобы облегчить поиск вывода в сообщении об ошибке.
  • SELECT (ELT(6668=6668,1)) — подзапрос, который возвращает 1, если условие 6668=6668 истинно. ELT — функция, возвращающая N-й элемент из списка; здесь список состоит из одного элемента 1. Фактически это проверка истинности, которая всегда возвращает 1.
  • -- - — комментарий, который отсекает оставшуюся часть оригинального SQL-запроса, чтобы избежать синтаксических ошибок.

При выполнении этого кода MySQL попытается обработать EXTRACTVALUE с некорректным XML и сгенерирует ошибку, в тексте которой будет содержаться результат CONCAT, то есть ~1~. Именно так злоумышленник может узнать значение, возвращаемое подзапросом.

Как работает error-based SQL-инъекция через EXTRACTVALUE?

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

Типичный сценарий атаки:

  1. Злоумышленник находит параметр, уязвимый для SQL-инъекции.
  2. Внедряет конструкцию с EXTRACTVALUE, где второй аргумент содержит CONCAT с полезной нагрузкой.
  3. СУБД выполняет подзапрос, получает данные (например, версию БД, имя пользователя, хеши паролей).
  4. Эти данные попадают в сообщение об ошибке, которое видит атакующий.

Важно отметить, что для успешной эксплуатации необходимо, чтобы приложение выводило ошибки СУБД пользователю. В противном случае атака может быть слепой (blind), и тогда используются другие техники.

Примеры полезных нагрузок

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

  • AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e)) — получение версии MySQL.
  • AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT user()), 0x7e)) — получение текущего пользователя БД.
  • AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e)) — получение имени текущей базы данных.
  • AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT table_name FROM information_schema.tables LIMIT 1), 0x7e)) — извлечение имён таблиц.

Все эти конструкции работают по одному принципу: вызывают ошибку, содержащую нужные данные.

Ограничения и особенности

Функция EXTRACTVALUE имеет ограничение на длину выводимой строки — обычно 32 символа. Это связано с тем, что MySQL использует тип данных для сообщений об ошибках, ограниченный по длине. Поэтому для извлечения длинных значений (например, хешей паролей) приходится использовать посимвольное извлечение с помощью SUBSTRING и смещений.

Кроме того, начиная с MySQL 5.7.9, функция EXTRACTVALUE была объявлена устаревшей (deprecated), а в MySQL 8.0 удалена. Однако во многих старых системах она всё ещё доступна, что делает её популярной среди пентестеров.

Защита от SQL-инъекций через EXTRACTVALUE

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

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

Важно понимать, что EXTRACTVALUE — лишь один из многих инструментов в арсенале злоумышленников. Комплексный подход к безопасности приложений и баз данных — залог защиты от подобных атак.

Заключение

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

Источники