Что такое EXTRACTVALUE и при чём тут SQL-инъекция
Функция EXTRACTVALUE — это встроенная функция MySQL, предназначенная для работы с XML. Она принимает два строковых аргумента: фрагмент XML-разметки и выражение XPath (локатор). Функция возвращает текст (CDATA) первого текстового узла, который является дочерним для элемента или элементов, соответствующих XPath-выражению.
Однако злоумышленники научились использовать эту функцию для проведения так называемых error-based SQL-инъекций. Суть метода в том, что при передаче некорректного XPath-выражения MySQL генерирует ошибку, в тексте которой может содержаться результат выполнения подзапроса. Это позволяет атакующему извлекать данные из базы, даже если прямой вывод информации не отображается на странице.
Рассматриваемый payload %' AND EXTRACTVALUE(3444,CONCAT(0x7e,((SELECT (ELT(3444=3444,1)))),0x7e))-- - — это классический пример такой инъекции. Давайте разберём его по частям.
Разбор payload по элементам
Payload выглядит так:
%' AND EXTRACTVALUE(3444,CONCAT(0x7e,((SELECT (ELT(3444=3444,1)))),0x7e))-- -
Разберём каждый компонент:
%'— символ процента и одинарная кавычка. Обычно используется для завершения строкового литерала в уязвимом запросе. Символ%может быть частью LIKE-шаблона, а кавычка закрывает строку, позволяя внедрить произвольный SQL-код.AND— логический оператор, который добавляет условие к исходному запросу. Если исходный запрос был истинным, добавлениеAND ...не изменит результат, но выполнит внедрённую функцию.EXTRACTVALUE(3444, CONCAT(...))— вызов уязвимой функции. Первый аргумент3444— произвольное число (фрагмент XML), второй аргумент — XPath-выражение, которое формируется динамически черезCONCAT.CONCAT(0x7e, ..., 0x7e)— конкатенация строк.0x7e— это шестнадцатеричное представление символа~(тильда). Тильда используется как маркер, чтобы облегчить поиск выводимых данных в сообщении об ошибке.(SELECT (ELT(3444=3444,1)))— подзапрос, который возвращает результат функцииELT.ELT(N, str1, str2, ...)возвращает N-ю строку из списка. В данном случаеELT(3444=3444, 1)— условие3444=3444всегда истинно (возвращает 1), поэтомуELT(1, 1)вернёт строку'1'. Это простейший пример; на практике вместо1может быть подзапрос, извлекающий данные (например, имя пользователя, хеш пароля).-- -— комментарий. Два дефиса с пробелом (или-- -) закомментируют остаток исходного запроса, чтобы не нарушать синтаксис.
Как это работает: пошагово
Предположим, уязвимый запрос выглядит так:
SELECT * FROM users WHERE name = '$input';
Если передать в $input наш payload, запрос превратится в:
SELECT * FROM users WHERE name = '%' AND EXTRACTVALUE(3444,CONCAT(0x7e,((SELECT (ELT(3444=3444,1)))),0x7e))-- -';
MySQL выполнит:
- Условие
name = '%'— вероятно, ложно, но это не важно, так как далее идётAND. - Функция
EXTRACTVALUEпопытается интерпретировать второй аргумент как XPath. Строка, переданная в XPath, будет выглядеть как~1~(тильда, результат ELT, тильда). - Выражение
~1~не является допустимым XPath, поэтому MySQL сгенерирует ошибку:XPATH syntax error: '~1~'. - В тексте ошибки появится значение
~1~, которое можно увидеть в ответе сервера (если ошибки выводятся).
Таким образом, атакующий может заменить 1 в ELT на любой подзапрос, например (SELECT password FROM users LIMIT 1), и получить его результат в сообщении об ошибке.
Зачем нужны 0x7e и ELT
0x7e (тильда) служит разделителем. Поскольку XPath-ошибка выводит строку целиком, тильды помогают легко найти начало и конец извлечённых данных в длинном сообщении об ошибке. Кроме того, тильда не является специальным символом в XPath и не вызовет дополнительных проблем.
ELT — это функция, которая возвращает N-й элемент из списка. В контексте инъекции она используется для преобразования результата подзапроса в строку, которую можно передать в XPath. Например, ELT(1, (SELECT user())) вернёт имя текущего пользователя MySQL. Если результат подзапроса не строка, ELT автоматически приведёт его к строковому типу.
В простейшем случае ELT(3444=3444,1) — это демонстрация работоспособности инъекции: условие всегда истинно, поэтому возвращается 1. Это позволяет проверить, уязвим ли параметр, не извлекая реальные данные.
Какие данные можно извлечь
С помощью этой техники атакующий может получить практически любую информацию из базы данных, к которой у него есть доступ через SQL-запросы. Например:
- Версию MySQL:
SELECT version() - Имя текущего пользователя:
SELECT user() - Имя базы данных:
SELECT database() - Список таблиц:
SELECT table_name FROM information_schema.tables - Данные из конкретных таблиц (логины, пароли, персональные данные).
Для каждого из этих значений потребуется отдельный запрос, так как error-based инъекция обычно возвращает только один результат за раз (если не использовать групповую конкатенацию).
Как защититься от error-based SQL-инъекций
Основная причина уязвимости — передача пользовательского ввода в SQL-запрос без должной обработки. Вот ключевые меры защиты:
- Использование подготовленных выражений (prepared statements) с параметризацией. Это самый надёжный способ, так как данные и код разделяются на уровне драйвера базы данных.
- Экранирование специальных символов с помощью функций вроде
mysqli_real_escape_string(для MySQL). Однако этот метод менее надёжен, чем подготовленные выражения, и требует осторожности. - Валидация и фильтрация входных данных — например, если параметр должен быть числом, приводите его к числу и проверяйте диапазон.
- Отключение вывода ошибок базы данных на продакшене. Даже если инъекция возможна, без вывода ошибок атакующему будет сложнее извлечь данные (но это не устраняет уязвимость).
- Использование ORM или query builder, которые по умолчанию применяют параметризацию.
- Регулярное обновление СУБД и фреймворков — иногда уязвимости возникают из-за ошибок в самом ПО.
Важно понимать, что EXTRACTVALUE — не единственная функция, используемая для error-based инъекций. Аналогично применяются UPDATEXML, GTID_SUBSET и другие. Поэтому защита должна быть комплексной и не полагаться на «чёрные списки» функций.
Заключение
Payload %' AND EXTRACTVALUE(3444,CONCAT(0x7e,((SELECT (ELT(3444=3444,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции через функцию EXTRACTVALUE. Он демонстрирует, как злоумышленник может использовать ошибки XPath для извлечения данных из базы. Понимание механики таких атак помогает разработчикам и администраторам лучше защищать свои приложения. Главный совет: всегда используйте параметризованные запросы и не выводите ошибки базы данных конечным пользователям.
Комментарии
—Войдите, чтобы оставить комментарий