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

Функция EXTRACTVALUE появилась в MySQL 5.1 как инструмент для работы с XML-данными. Она извлекает значение из XML-документа по заданному XPath-выражению. Синтаксис простой:

EXTRACTVALUE(XML_документ, XPath_выражение)

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

Механизм error-based инъекции через EXTRACTVALUE

Классический пример: злоумышленник внедряет в уязвимый параметр запроса конструкцию вида:

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

Разберём по частям:

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

При выполнении такого запроса MySQL пытается интерпретировать строку, начинающуюся с тильды, как XPath. Поскольку это недопустимый синтаксис, СУБД возвращает ошибку вида:

ERROR 1105 (HY000): XPATH syntax error: '~1~'

В сообщении об ошибке мы видим результат выполнения подзапроса — число 1, обрамлённое тильдами. Именно это и нужно атакующему: он может подставить любой другой подзапрос и получить его результат в тексте ошибки.

Примеры эксплуатации

Рассмотрим, как с помощью EXTRACTVALUE можно вытащить имя текущей базы данных. Предположим, уязвимый параметр — id. Внедряем:

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

В ответе получим ошибку с названием базы. Аналогично можно извлечь версию MySQL:

AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT version()),0x7e))-- -

Более сложные запросы позволяют посимвольно выгружать содержимое таблиц. Например, для получения первого символа имени пользователя из таблицы users:

AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT SUBSTRING(username,1,1) FROM users LIMIT 0,1),0x7e))-- -

Ограничение длины вывода в ошибке (обычно 32 символа) обходится с помощью функций SUBSTRING и LIMIT.

Почему это работает?

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

Стоит отметить, что аналогичными свойствами обладают функции UPDATEXML и GTID_SUBSET. Все они эксплуатируются в error-based атаках.

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

Меры защиты стандартны для любого типа SQL-инъекций, но с учётом специфики error-based:

  1. Используйте подготовленные выражения (prepared statements). Параметризация запросов исключает возможность внедрения SQL-кода.
  2. Отключите вывод ошибок СУБД в продакшене. Ошибки должны логироваться, но не показываться пользователю.
  3. Ограничьте права пользователя БД. Приложение должно работать с минимально необходимыми привилегиями.
  4. Валидируйте и фильтруйте входные данные. Особенно это касается числовых параметров, где ожидается только число.
  5. Регулярно обновляйте MySQL. В новых версиях некоторые функции могут быть удалены или изменены, что снижает риск.

Также рекомендуется использовать WAF (Web Application Firewall) для блокировки подозрительных конструкций, хотя полагаться только на него нельзя.

Заключение

EXTRACTVALUE — мощный инструмент для работы с XML, но в руках злоумышленника он превращается в средство для извлечения конфиденциальных данных. Понимание механизма error-based инъекций помогает разработчикам и администраторам правильно выстраивать защиту. Главное правило: никогда не доверяйте пользовательскому вводу и не показывайте ошибки базы данных конечным пользователям.

Источники