Что такое 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-инъекциях по нескольким причинам:
- Вывод данных в ошибке. Сообщение об ошибке XPATH содержит переданную строку, что позволяет злоумышленнику видеть результаты подзапросов.
- Обход фильтров. Многие системы защиты фильтруют ключевые слова вроде UNION SELECT, но редко блокируют EXTRACTVALUE или подобные функции.
- Простота использования. Не требуется угадывать количество столбцов, как в UNION-инъекциях. Достаточно внедрить функцию в существующий запрос.
- Работа в слепую. Даже если приложение не выводит ошибки напрямую, их можно использовать в 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 можно вывести данные в сообщении об ошибке. Понимание таких векторов атак помогает разработчикам и специалистам по безопасности правильно выстраивать защиту. Помните: лучшая защита — параметризованные запросы и минимизация привилегий базы данных.
Комментарии
—Войдите, чтобы оставить комментарий